#include "Parser.h"
#include <string.h>
#include "Assembler.h"
#include "MachineTypes.h"
#include "Constexpr.h"
#include "NumberSet.h"

Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUnits)
	: mErrors(errors), mScanner(scanner), mCompilationUnits(compilationUnits), mParent(nullptr)
{
	mGlobals = new DeclarationScope(compilationUnits->mScope, SLEVEL_STATIC);
	mScope = mGlobals;
	mTemplateScope = nullptr;

	mCodeSection = compilationUnits->mSectionCode;
	mDataSection = compilationUnits->mSectionData;
	mBSSection = compilationUnits->mSectionBSS;

	mUnrollLoop = 0;
	mUnrollLoopPage = false;
	mInlineCall = false;
	mCompilerOptionSP = 0;
	mThisPointer = nullptr;
	mFunction = nullptr;
	mFunctionType = nullptr;
	mLambda = nullptr;
	mCaptureScope = nullptr;
	mTempVars = nullptr;

	for (int i = 0; i < 256; i++)
		mCharMap[i] = i;
}

Parser::~Parser(void)
{

}

Parser* Parser::Clone(void)
{
	Parser* p = new Parser(mErrors, new Scanner(mErrors, mScanner->mPreprocessor), mCompilationUnits);

	p->mGlobals = mGlobals;
	p->mScope = mScope;
	p->mCompilerOptions = mCompilerOptions;
	p->mCodeSection = mCodeSection;
	p->mDataSection = mDataSection;
	p->mBSSection = mBSSection;

	return p;
}

Declaration* Parser::FindBaseMemberFunction(Declaration* dec, Declaration* mdec)
{
	const Ident* ident = mdec->mIdent;

	if (ident->mString[0] == '~')
	{
		// this is the destructor, need special search

		Declaration * pdec = dec;
		Declaration * pmdec = nullptr;

		while (pdec->mBase && !pmdec)
		{
			pdec = pdec->mBase->mBase;
			pmdec = pdec->mScope->Lookup(pdec->mIdent->PreMangle("~"));
		}

		return pmdec;
	}
	else
	{
		Declaration * pdec = dec;
		Declaration	* pmdec = nullptr;

		while (pdec->mBase && !pmdec)
		{
			pdec = pdec->mBase->mBase;
			pmdec = pdec->mScope->Lookup(ident);

			while (pmdec && !mdec->mBase->IsDerivedFrom(pmdec->mBase))
				pmdec = pmdec->mNext;

			if (pmdec)
				return pmdec;
		}

		return pmdec;
	}
}

Declaration * Parser::AddMemberFunction(Declaration* dec, Declaration* mdec)
{
	Declaration* pmdec = FindBaseMemberFunction(dec, mdec);
	if (pmdec)
		mdec->mBase->mFlags |= pmdec->mBase->mFlags & DTF_VIRTUAL;

	const Ident* dtorident = dec->mIdent->PreMangle("~");;
	const Ident* ctorident = dec->mIdent->PreMangle("+");;

	if (mdec->mIdent == ctorident)
	{
		// Check constructors
		Declaration* ctdec = mdec->mBase;
		Declaration* tparam = ctdec->mParams->mNext;

		if (!tparam && !dec->mDefaultConstructor)
			dec->mDefaultConstructor = mdec;
		else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_REFERENCE && dec->IsConstSame(tparam->mBase->mBase) && !dec->mCopyConstructor)
			dec->mCopyConstructor = mdec;
		else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_RVALUEREF && dec->IsConstSame(tparam->mBase->mBase) && !dec->mMoveConstructor)
			dec->mMoveConstructor = mdec;
	}
	else if (mdec->mIdent == dtorident && !dec->mDestructor)
	{
		dec->mDestructor = mdec;
	}

	Declaration* gdec = mCompilationUnits->mScope->Insert(mdec->mQualIdent, mdec);
	if (gdec)
	{
		if (gdec->mType == DT_CONST_FUNCTION)
		{
			Declaration* pcdec = nullptr;
			Declaration* pdec = gdec;

			while (pdec && !mdec->mBase->IsSameParams(pdec->mBase))
			{
				pcdec = pdec;
				pdec = pdec->mNext;
			}

			if (!pdec)
				pcdec->mNext = mdec;

			dec->mScope->Insert(mdec->mIdent, gdec);
			if (dec->mConst)
				dec->mConst->mScope->Insert(mdec->mIdent, gdec);

			if (pdec)
				return pdec;
		}
		else
		{
			mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent);
			mErrors->Error(gdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
		}
	}
	else
		dec->mScope->Insert(mdec->mIdent, mdec);

	return mdec;
}

Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaration* ptempl)
{
	const Ident* structName = nullptr;

	Declaration	*	dec = new Declaration(mScanner->mLocation, dt);

	bool	needVTable = false;

	mScanner->NextToken();
	if (mScanner->mToken == TK_IDENT)
	{
		structName = mScanner->mTokenIdent;
		mScanner->NextToken();
		Declaration* edec = mScope->Lookup(structName);
		if (edec && edec->mTemplate)
		{
			mTemplateScope->Insert(structName, dec);

			dec->mIdent = structName;
			dec->mQualIdent = mScope->Mangle(structName->Mangle(mTemplateScope->mName->mString));
			dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, dec->mQualIdent);
		}
		else if (edec && mScanner->mToken != TK_OPEN_BRACE && mScanner->mToken != TK_COLON)
		{
			dec = edec;
		}
		else
		{
			Declaration* pdec = mScope->Insert(structName, dec);
			if (pdec)
			{
				if (pdec->mType == dt && !(pdec->mFlags & DTF_DEFINED))
				{
					dec = pdec;
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Error duplicate struct declaration", structName);
					mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
				}
			}
		}
	}
	else if ((mCompilerOptions & COPT_CPLUSPLUS) && mScope->mLevel < SLEVEL_CLASS)
	{
		mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid unnamed struct on global level");
	}

	if (!dec->mIdent || !dec->mScope)
	{
		dec->mIdent = structName;
		dec->mQualIdent = mScope->Mangle(structName);
		dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, dec->mQualIdent);
	}

	if (ptempl)
	{
		ptempl->mBase = dec;

		if (mScanner->mToken == TK_LESS_THAN)
		{
			int level = 0;
			do {
				if (mScanner->mToken == TK_LESS_THAN)
					level++;
				else if (mScanner->mToken == TK_GREATER_THAN)
					level--;
				mScanner->NextToken();
			} while (level > 0);
		}
	}

	if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_COLON)
	{
		mScanner->NextToken();
		uint64	pflags = flags;

		if (ConsumeTokenIf(TK_PUBLIC))
			pflags &= ~(DTF_PRIVATE | DTF_PROTECTED);
		else if (ConsumeTokenIf(TK_PROTECTED))
			pflags = (pflags & ~DTF_PRIVATE) | DTF_PROTECTED;
		else if (ConsumeTokenIf(TK_PRIVATE))
			pflags |= DTF_PRIVATE | DTF_PROTECTED;

		Declaration* pdec = ParseBaseTypeDeclaration(0, false);
		if (pdec)
		{
			if (pdec->mType == DT_TYPE_STRUCT)
			{
				Declaration* bcdec = new Declaration(mScanner->mLocation, DT_BASECLASS);
				bcdec->mBase = pdec;
				bcdec->mFlags = pflags;
				
				dec->mScope->UseScope(pdec->mScope);

				if (pdec->mVTable)
					needVTable = true;

				dec->mSize = pdec->mSize;

				dec->mBase = bcdec;
			}
			else
				mErrors->Error(mScanner->mLocation, ERRO_NOT_A_BASE_CLASS, "Not a base class", dec->mIdent);
		}
	}

	if (mScanner->mToken == TK_OPEN_BRACE)
	{
		Declaration* pthis = nullptr;
		
		DeclarationScope* oscope = mScope;

		if (mCompilerOptions & COPT_CPLUSPLUS)
		{
			pthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			pthis->mFlags |= DTF_CONST | DTF_DEFINED;
			pthis->mBase = dec;
			pthis->mSize = 2;

			dec->mScope->mParent = mScope;
			mScope = dec->mScope;
		}

		mScanner->NextToken();
		if (ConsumeTokenIf(TK_CLOSE_BRACE))
		{
			dec->mParams = nullptr;
		}
		else
		{
			int	bitsleft = 0;

			Declaration* mlast = nullptr;
			for (;;)
			{
				do {} while (ConsumeTokenIf(TK_SEMICOLON));

				if (ConsumeTokenIf(TK_PUBLIC))
				{
					flags &= ~(DTF_PRIVATE | DTF_PROTECTED);
					ConsumeToken(TK_COLON);
				}
				else if (ConsumeTokenIf(TK_PROTECTED))
				{
					flags &= ~DTF_PRIVATE;
					flags |= DTF_PROTECTED;
					ConsumeToken(TK_COLON);
				}
				else if (ConsumeTokenIf(TK_PRIVATE))
				{
					flags |= DTF_PRIVATE | DTF_PROTECTED;
					ConsumeToken(TK_COLON);
				}
				else if (ConsumeTokenIf(TK_FRIEND))
				{
					mScope = oscope;
					Declaration* fdec = ParseDeclaration(nullptr, true, false, false);
					if (fdec->mType == DT_ANON)
						fdec = fdec->mBase;
					dec->mFriends.Push(fdec);
					mScope = dec->mScope;
				}
				else if (ConsumeTokenIf(TK_CLOSE_BRACE))
				{
					break;
				}
				else if (ConsumeTokenIf(TK_TEMPLATE))
				{
					Declaration	*	tdec = ParseTemplateDeclaration(pthis);
				}
				else if (ConsumeTokenIf(TK_STATIC_ASSERT))
				{
					ParseStaticAssert();
				}
				else
				{
					Declaration* mdec = ParseDeclaration(nullptr, false, false, true, pthis);
					if (mdec)
					{
						mdec->mQualIdent = dec->mScope->Mangle(mdec->mIdent);

						int	offset = dec->mSize;
						if (dt == DT_TYPE_UNION)
							offset = 0;

						if (mdec->mBase->mType == DT_TYPE_FUNCTION)
						{
							mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED);

							if (mdec->mBase->mFlags & DTF_VIRTUAL)
								needVTable = true;

							mdec->mType = DT_CONST_FUNCTION;
							mdec->mSection = mCodeSection;
							mdec->mFlags |= DTF_GLOBAL;
//							mdec->mBase->mFlags |= DTF_FUNC_THIS;

							if (mCompilerOptions & COPT_NATIVE)
								mdec->mFlags |= DTF_NATIVE;

							AddMemberFunction(dec, mdec);
						}
						else if ((mCompilerOptions & COPT_CPLUSPLUS) && mdec->mType == DT_ANON)
						{
							mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED);

							ConsumeToken(TK_SEMICOLON);
							// anon element
						}
						else
						{
							while (mdec)
							{
								mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED);

								if (!(mdec->mBase->mFlags & DTF_DEFINED))
									mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Undefined type used in struct member declaration");

								if (mdec->mType != DT_VARIABLE)
								{
									mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Named structure element expected");
									break;
								}

								if (mdec->mFlags & DTF_STATIC)
								{
									mdec->mFlags |= DTF_GLOBAL;
									mdec->mVarIndex = -1;
									mdec->mQualIdent = mScope->Mangle(mdec->mIdent);

									if (mdec->mValue && (mdec->mBase->mFlags & DTF_CONST))
									{
										if (mdec->mBase->IsNumericType())
										{
											if (mdec->mValue->mType == EX_CONSTANT)
											{
												mdec->mType = mdec->mValue->mDecValue->mType;
												mdec->mInteger = mdec->mValue->mDecValue->mInteger;
											}
										}
										else if (dec->mBase->mType == DT_TYPE_POINTER)
										{
											if (dec->mValue->mType == EX_CONSTANT)
											{
												if (dec->mValue->mDecValue->mType == DT_CONST_ADDRESS || dec->mValue->mDecValue->mType == DT_CONST_POINTER)
												{
													mdec->mType = mdec->mValue->mDecValue->mType;
													mdec->mInteger = mdec->mValue->mDecValue->mInteger;
												}
											}
										}
									}

									Declaration * pdec = mCompilationUnits->mScope->Insert(mdec->mQualIdent, mdec);

									if (pdec)
										mdec = pdec;

									Declaration* odec = dec->mScope->Insert(mdec->mIdent, mdec);
									if (odec)
									{
										mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent);
										mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
									}
								}
								else
								{
									mdec->mType = DT_ELEMENT;
									mdec->mOffset = offset;

									if (mdec->mBits)
									{
										if (mdec->mBits <= 8)
										{
											if (bitsleft == 0)
											{
												bitsleft = 8 - mdec->mBits;
												offset++;
											}
											else if (bitsleft >= mdec->mBits)
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft -= mdec->mBits;
											}
											else
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft = 8 + bitsleft - mdec->mBits;
												offset++;
											}
										}
										else if (mdec->mBits <= 16)
										{
											if (bitsleft == 0)
											{
												bitsleft = 16 - mdec->mBits;
												offset += 2;
											}
											else if (bitsleft + 8 >= mdec->mBits)
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft = bitsleft + 8 - mdec->mBits;
												offset++;
											}
											else if (mdec->mOffset >= 2)
											{
												mdec->mOffset -= 2;
												mdec->mShift = 16 - bitsleft;
												bitsleft = bitsleft + 16 - mdec->mBits;
												offset += 2;
											}
											else
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft = bitsleft + 16 - mdec->mBits;
												offset += 2;
											}
										}
										else if (mdec->mBits <= 24)
										{
											if (bitsleft == 0)
											{
												bitsleft = 24 - mdec->mBits;
												offset += 3;
											}
											else if (bitsleft + 16 >= mdec->mBits)
											{
												if (mdec->mOffset >= 2)
												{
													mdec->mOffset -= 2;
													mdec->mShift = 16 - bitsleft;
													bitsleft = bitsleft + 16 - mdec->mBits;
													offset += 2;
												}
												else
												{
													mdec->mOffset--;
													mdec->mShift = 8 - bitsleft;
													bitsleft = bitsleft + 16 - mdec->mBits;
													offset += 2;
												}
											}
											else if (mdec->mOffset >= 2)
											{
												mdec->mOffset -= 2;
												mdec->mShift = 16 - bitsleft;
												bitsleft = bitsleft + 24 - mdec->mBits;
												offset += 3;
											}
											else
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft = bitsleft + 24 - mdec->mBits;
												offset += 3;
											}
										}
										else
										{
											if (bitsleft == 0)
											{
												bitsleft = 32 - mdec->mBits;
												offset += 4;
											}
											else if (bitsleft + 24 >= mdec->mBits)
											{
												mdec->mOffset--;
												mdec->mShift = 8 - bitsleft;
												bitsleft = bitsleft + 24 - mdec->mBits;
												offset+=3;
											}
											else
											{
												bitsleft = 32 - mdec->mBits;
												offset += mdec->mBase->mSize;
											}
										}

										if (mdec->mBits == 24 && mdec->mOffset > 0 && mdec->mShift == 0)
										{
											mdec->mOffset--;
											mdec->mShift = 8;
										}

										if (mdec->mShift == 0 && mdec->mBits == 8 * mdec->mSize)
											mdec->mBits = 0;
									}
									else
									{
										int alignment = mdec->mBase->mAlignment;
										if (alignment == 0)
											alignment = 1;

										bitsleft = 0;
										if (mdec->mBase->mType == DT_TYPE_ARRAY && mdec->mBase->mBase->IsSimpleType() && mdec->mBase->mBase->mSize > 1)
											alignment = mdec->mBase->mBase->mSize;

										offset = (offset + alignment - 1) & ~(alignment - 1);
										offset += mdec->mBase->mSize;

										if (alignment > dec->mAlignment)
											dec->mAlignment = alignment;
									}

									if (offset > dec->mSize)
										dec->mSize = offset;

									Declaration* odec = dec->mScope->Insert(mdec->mIdent, mdec);
									if (odec)
									{
										mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent);
										mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
									}

									if (dec->mConst)
									{
										Declaration* cmdec = mdec->Clone();
										cmdec->mBase = mdec->mBase->ToConstType();

										dec->mConst->mScope->Insert(cmdec->mIdent, cmdec);
										dec->mConst->mSize = dec->mSize;
									}

									if (mlast)
										mlast->mNext = mdec;
									else
										dec->mParams = mdec;
									mlast = mdec;
								}

								mdec = mdec->mNext;
							}

							if (mScanner->mToken == TK_SEMICOLON)
								mScanner->NextToken();
							else
							{
								mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected");
								break;
							}
						}
					}
				}
			}

			if (mlast)
				mlast->mNext = nullptr;
			else
				dec->mParams = nullptr;
		}

		dec->SetDefined();
		if (dec->mConst)
			dec->mConst->mSize = dec->mSize;

		if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mType == DT_TYPE_STRUCT && dec->mIdent)
		{
			if (needVTable)
			{
				Declaration* vdec = mCompilationUnits->mVTableScope->Lookup(dec->mQualIdent);
				if (!vdec)
				{
					vdec = new Declaration(dec->mLocation, DT_VTABLE);

					if (dec->mBase)
					{
						vdec->mBase = dec->mBase->mBase->mVTable;
						vdec->mSize = vdec->mBase->mSize;		
						vdec->mOffset = vdec->mBase->mOffset;
					}
					else
					{
						vdec->mOffset = 0;
					}

					vdec->mDefaultConstructor = new Declaration(dec->mLocation, DT_CONST_INTEGER);
					vdec->mDefaultConstructor->mBase = TheConstCharTypeDeclaration;
					vdec->mDefaultConstructor->mSize = 1;
					vdec->mDefaultConstructor->mInteger = -1;

					vdec->mClass = dec;
					vdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);
					vdec->mIdent = dec->mIdent;
					vdec->mQualIdent = dec->mQualIdent;
					mCompilationUnits->mVTableScope->Insert(vdec->mQualIdent, vdec);
				}

				dec->mVTable = vdec;

				if (!dec->mBase)
				{
					Declaration* mdec = dec->mParams;
					while (mdec)
					{
						mdec->mOffset++;
						mdec = mdec->mNext;
					}
					dec->mSize++;
					if (dec->mConst)
						dec->mConst->mSize = dec->mSize;
				}
				
				// make sure virtual destructors end up in vtable
				AddDefaultConstructors(pthis);

				dec->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
					{
						if (mdec->mType == DT_CONST_FUNCTION)
						{
							while (mdec)
							{
								if (mdec->mBase->mFlags & DTF_VIRTUAL)
								{
									if (mdec->mFlags & DTF_PURE_VIRTUAL)
										dec->mFlags |= DTF_PURE_VIRTUAL;

									Declaration* vpdec = vdec;
									Declaration* vmdec;
									if (mdec->mIdent->mString[0] == '~')
									{
										// this is the destructor, need special search

										vmdec = vpdec->mScope->Lookup(vpdec->mIdent->PreMangle("~"));
										while (!vmdec && vpdec->mBase)
										{
											vpdec = vpdec->mBase;
											vmdec = vpdec->mScope->Lookup(vpdec->mIdent->PreMangle("~"));
										}
									}
									else
									{
										vmdec = vpdec->mScope->Lookup(ident);
										while (!vmdec && vpdec->mBase)
										{
											vpdec = vpdec->mBase;
											vmdec = vpdec->mScope->Lookup(ident);
										}
									}

									Declaration* vmpdec = nullptr;

									while (vmdec && !mdec->mBase->IsDerivedFrom(vmdec->mBase))
									{
										vmpdec = vmdec;
										vmdec = vmdec->mNext;
									}

									if (!vmdec)
									{
										vmdec = mdec->Clone();
										vmdec->mNext = nullptr;
										vmdec->mDefaultConstructor = dec->mVTable;
										vmdec->mFlags |= DTF_NATIVE;

										if (vmpdec)
											vmpdec->mNext = vmdec;
										else
											vdec->mScope->Insert(ident, vmdec);
									}

									mdec->mVTable = vmdec;
								}

								mdec = mdec->mNext;
							}
						}
					}
				);				
			}
			else
				AddDefaultConstructors(pthis);

			if (pthis->mBase->mConst)
			{
				pthis->mBase->mConst->mDestructor = pthis->mBase->mDestructor;
				pthis->mBase->mConst->mDefaultConstructor = pthis->mBase->mDefaultConstructor;
				pthis->mBase->mConst->mCopyConstructor = pthis->mBase->mCopyConstructor;
				pthis->mBase->mConst->mMoveConstructor = pthis->mBase->mMoveConstructor;
				pthis->mBase->mConst->mVectorConstructor = pthis->mBase->mVectorConstructor;
				pthis->mBase->mConst->mVectorDestructor = pthis->mBase->mVectorConstructor;
				pthis->mBase->mConst->mVectorCopyConstructor = pthis->mBase->mVectorCopyConstructor;
				pthis->mBase->mConst->mVectorMoveConstructor = pthis->mBase->mVectorMoveConstructor;
			}

			// Lookup constructors, have same name as class
			Declaration* cdec = dec->mScope->Lookup(dec->mIdent->PreMangle("+"), SLEVEL_SCOPE);
			while (cdec)
			{
				if (cdec->mFlags & DTF_DEFINED)
					PrependMemberConstructor(pthis, cdec);
				cdec = cdec->mNext;
			}

			AppendMemberDestructor(pthis);

		}

		mScope = oscope;
	}

	if ((flags & ~dec->mFlags) == DTF_CONST)
		dec = dec->ToConstType();
	else if ((flags & ~dec->mFlags) == DTF_VOLATILE)
		dec = dec->ToVolatileType();

	return dec;
}

Declaration* Parser::ParseBaseTypeQualify(bool qualified, Declaration* dec, const Ident*& pident)
{
	while (dec && (dec->mType == DT_NAMESPACE || (qualified && (dec->mType == DT_TYPE_STRUCT || dec->mType == DT_TYPE_TEMPLATE)) && !dec->mTemplate) && ConsumeTokenIf(TK_COLCOLON))
	{
		if (ExpectToken(TK_IDENT))
		{
			pident = mScanner->mTokenIdent;
			if (dec->mType == DT_TYPE_TEMPLATE)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE);
				ndec->mFlags |= DTF_DEFINED;
				ndec->mBase = dec;
				ndec->mIdent = pident;
				dec = ndec;
			}
			else
				dec = dec->mScope->Lookup(pident);

			mScanner->NextToken();
		}
	}

	return dec;
}

Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified, Declaration* ptempl)
{
	Declaration* dec = nullptr;
	const Ident* pident = nullptr;

	switch (mScanner->mToken)
	{
	case TK_UNSIGNED:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mFlags = flags | DTF_DEFINED;
		mScanner->NextToken();
		if (mScanner->mToken == TK_INT)
		{
			dec->mSize = 2;
			mScanner->NextToken();
		}
		else if (mScanner->mToken == TK_SHORT)
		{
			dec->mSize = 2;
			mScanner->NextToken();
			ConsumeTokenIf(TK_INT);
		}
		else if (mScanner->mToken == TK_LONG)
		{
			dec->mSize = 4;
			mScanner->NextToken();
			ConsumeTokenIf(TK_INT);
		}
		else if (mScanner->mToken == TK_CHAR)
		{
			dec->mSize = 1;
			mScanner->NextToken();
		}
		else
			dec->mSize = 2;

		break;

	case TK_SIGNED:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		mScanner->NextToken();
		if (mScanner->mToken == TK_INT)
		{
			dec->mSize = 2;
			mScanner->NextToken();
		}
		else if (mScanner->mToken == TK_SHORT)
		{
			dec->mSize = 2;
			mScanner->NextToken();
			ConsumeTokenIf(TK_INT);
		}
		else if (mScanner->mToken == TK_LONG)
		{
			dec->mSize = 4;
			mScanner->NextToken();
			ConsumeTokenIf(TK_INT);
		}
		else if (mScanner->mToken == TK_CHAR)
		{
			dec->mSize = 1;
			mScanner->NextToken();
		}
		else
			dec->mSize = 2;
		break;

	case TK_CONST:
		mScanner->NextToken();
		return ParseBaseTypeDeclaration(flags | DTF_CONST, qualified);

	case TK_VOLATILE:
		mScanner->NextToken();
		return ParseBaseTypeDeclaration(flags | DTF_VOLATILE, qualified);

	case TK_LONG:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mSize = 4;
		mScanner->NextToken();
		if (ConsumeTokenIf(TK_UNSIGNED))
			dec->mFlags = flags | DTF_DEFINED;
		else if (ConsumeTokenIf(TK_SIGNED))
			dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		else
			dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		ConsumeTokenIf(TK_INT);
		break;

	case TK_SHORT:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mSize = 2;
		mScanner->NextToken();
		if (ConsumeTokenIf(TK_UNSIGNED))
			dec->mFlags = flags | DTF_DEFINED;
		else if (ConsumeTokenIf(TK_SIGNED))
			dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		else
			dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		ConsumeTokenIf(TK_INT);
		break;

	case TK_INT:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mSize = 2;
		dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		mScanner->NextToken();
		break;

	case TK_CHAR:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
		dec->mSize = 1;
		dec->mFlags = flags | DTF_DEFINED;
		mScanner->NextToken();
		break;

	case TK_BOOL:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_BOOL);
		dec->mSize = 1;
		dec->mFlags = flags | DTF_DEFINED;
		mScanner->NextToken();
		break;

	case TK_FLOAT:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_FLOAT);
		dec->mSize = 4;
		dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
		mScanner->NextToken();
		break;

	case TK_VOID:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_VOID);
		dec->mSize = 0;
		dec->mFlags = flags | DTF_DEFINED;
		mScanner->NextToken();
		break;

	case TK_AUTO:
		dec = new Declaration(mScanner->mLocation, DT_TYPE_AUTO);
		dec->mSize = 0;
		dec->mFlags = flags | DTF_DEFINED;
		mScanner->NextToken();
		break;

	case TK_DECLTYPE:
	{
		mScanner->NextToken();
		Expression* exp = ParseExpression(true);
		dec = exp->mDecType;
	}
		break;

	case TK_COLCOLON:
	case TK_IDENT:
	{
		DeclarationScope* scope = mScope;
		if (mScanner->mToken == TK_COLCOLON)
		{
			mScanner->NextToken();
			while (scope->mLevel > SLEVEL_STATIC)
				scope = scope->mParent;
			if (!ExpectToken(TK_IDENT))
				break;
		}

		pident = mScanner->mTokenIdent;
		mScanner->NextToken();

		if (mTemplateScope)
		{
			dec = mTemplateScope->Lookup(pident);
			if (dec && mScanner->mToken == TK_LESS_THAN && !dec->mTemplate)
				dec = nullptr;
		}

		if (!dec && mThisPointer && !mScope->Lookup(pident, SLEVEL_FUNCTION))
		{
			int offset;
			uint64 flags;

			if (mThisPointer->mType == DT_ARGUMENT)
				dec = MemberLookup(mThisPointer->mBase->mBase, mScanner->mTokenIdent, offset, flags);
			else if (mThisPointer->mType == DT_TYPE_POINTER)
				dec = MemberLookup(mThisPointer->mBase, mScanner->mTokenIdent, offset, flags);

			if (dec && dec->mTemplate)
				dec = ParseTemplateExpansion(dec->mTemplate, nullptr);
		}

		if (!dec)
		{
			dec = mScope->Lookup(pident);
			if (dec && dec->mType == DT_CONST_FUNCTION && mScope->mLevel == SLEVEL_CLASS)
				dec = mScope->mParent->Lookup(pident);

			dec = ParseBaseTypeQualify(qualified, dec, pident);

			if (dec && dec->mTemplate)
				dec = ParseTemplateExpansion(dec->mTemplate, nullptr);
		}

		dec = ParseBaseTypeQualify(qualified, dec, pident);

		if (dec)
		{
			if (dec->mType <= DT_TYPE_FUNCTION)
			{
				if ((flags & ~dec->mFlags) == DTF_CONST)
					dec = dec->ToConstType();
				else if ((flags & ~dec->mFlags) == DTF_VOLATILE)
					dec = dec->ToVolatileType();
				else if (dec->IsSimpleType() && (flags & ~dec->mFlags))
				{
					Declaration* ndec = new Declaration(dec->mLocation, dec->mType);
					ndec->mFlags = dec->mFlags | flags;
					ndec->mSize = dec->mSize;
					ndec->mBase = dec->mBase;
					dec = ndec;
				}
				else if (dec->mType == DT_TYPE_STRUCT && (flags & ~dec->mFlags))
				{
					if ((flags & ~dec->mFlags) == DTF_CONST)
						dec = dec->ToConstType();
					else if ((flags & ~dec->mFlags) == DTF_VOLATILE)
						dec = dec->ToVolatileType();
					else
					{
						Declaration* ndec = new Declaration(dec->mLocation, dec->mType);
						ndec->mFlags = dec->mFlags | flags;
						ndec->mSize = dec->mSize;
						ndec->mBase = dec->mBase;
						ndec->mScope = dec->mScope;
						ndec->mParams = dec->mParams;
						ndec->mIdent = dec->mIdent;
						ndec->mQualIdent = dec->mQualIdent;
						dec = ndec;
					}
				}
			}
			else if (dec->mType == DT_PACK_TEMPLATE || dec->mType == DT_PACK_TYPE)
			{
				if ((flags & ~dec->mFlags) == DTF_CONST)
					dec = dec->ToConstType();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", dec->mQualIdent);
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", pident);

		break;
	}

	case TK_ENUM:
	{
		dec = new Declaration(mScanner->mLocation, DT_TYPE_ENUM);
		dec->mFlags = flags;
		dec->mSize = 1;
		dec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

		bool	classTemplate = false, baseClass = false;

		mScanner->NextToken();

		if (mCompilerOptions & COPT_CPLUSPLUS)
		{
			if (ConsumeTokenIf(TK_CLASS) || ConsumeTokenIf(TK_STRUCT))
				classTemplate = true;
		}
		
		if (mScanner->mToken == TK_IDENT)
		{
			dec->mIdent = mScanner->mTokenIdent;
			dec->mQualIdent = mScope->Mangle(dec->mIdent);
			
			Declaration* odec = mScope->Insert(dec->mIdent, dec);
			if (odec)
			{
				mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate name", dec->mIdent);
				mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
			}
			mScanner->NextToken();
		}

		if (mCompilerOptions & COPT_CPLUSPLUS)
		{
			if (ConsumeTokenIf(TK_COLON))
			{
				Declaration* pdec = ParseBaseTypeDeclaration(0, false);
				if (pdec->mType == DT_TYPE_INTEGER)
				{
					dec->mSize = pdec->mSize;
					dec->mFlags |= pdec->mFlags & DTF_SIGNED;
					baseClass = true;
				}
				else
					mErrors->Error(pdec->mLocation, EERR_INCOMPATIBLE_TYPES, "Integer base type expected");
			}
		}

		int	nitem = 0;
		if (mScanner->mToken == TK_OPEN_BRACE)
		{
			mScanner->NextToken();
			if (mScanner->mToken == TK_IDENT)
			{
				int64	minValue = 0, maxValue = 0;

				for (;;)
				{
					Declaration* cdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
					cdec->mBase = dec;
					cdec->mSize = 2;
					if (mScanner->mToken == TK_IDENT)
					{
						cdec->mIdent = mScanner->mTokenIdent;
						cdec->mQualIdent = mScope->Mangle(cdec->mIdent);
						Declaration* odec;
						if (classTemplate)
							odec = dec->mScope->Insert(cdec->mIdent, cdec);
						else
							odec = mScope->Insert(cdec->mIdent, cdec);

						if (odec)
						{
							mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate declaration", mScanner->mTokenIdent->mString);
							mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
						}
						mScanner->NextToken();
					}
					if (mScanner->mToken == TK_ASSIGN)
					{
						mScanner->NextToken();
						Expression* exp = ParseRExpression();
						if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
							nitem = int(exp->mDecValue->mInteger);
						else
							mErrors->Error(mScanner->mLocation, EERR_CONSTANT_TYPE, "Integer constant expected");
					}
					cdec->mInteger = nitem++;
					if (cdec->mInteger < minValue)
						minValue = cdec->mInteger;
					else if (cdec->mInteger > maxValue)
						maxValue = cdec->mInteger;

					cdec->mNext = dec->mParams;
					dec->mParams = cdec;

					if (mScanner->mToken == TK_COMMA)
					{
						mScanner->NextToken();
						if (mScanner->mToken == TK_CLOSE_BRACE)
							break;
					}
					else
						break;
				}

				dec->mMinValue = minValue;
				dec->mMaxValue = maxValue;

				if (minValue < 0)
				{
					if (baseClass)
					{
						if (dec->mFlags & DTF_SIGNED)
						{
							if (minValue < -128 && dec->mSize == 1)
								mErrors->Error(mScanner->mLocation, EWARN_INVALID_VALUE_RANGE, "Enum constant out of bounds");
						}
						else
							mErrors->Error(mScanner->mLocation, EWARN_INVALID_VALUE_RANGE, "Enum constant out of bounds");
					}
					else
					{
						dec->mFlags |= DTF_SIGNED;
						if (minValue < -128 || maxValue > 127)
							dec->mSize = 2;
					}
				}
				else if (maxValue > 255)
				{
					if (baseClass)
					{
						if (dec->mSize == 1)
							mErrors->Error(mScanner->mLocation, EWARN_INVALID_VALUE_RANGE, "Enum constant out of bounds");
					}
					else
						dec->mSize = 2;
				}
			}

			if (mScanner->mToken == TK_CLOSE_BRACE)
				mScanner->NextToken();
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");

		dec->mFlags |= DTF_DEFINED;
		break;
	}
	case TK_STRUCT:
		dec = ParseStructDeclaration(flags, DT_TYPE_STRUCT, ptempl);
		break;
	case TK_CLASS:
		dec = ParseStructDeclaration(flags | DTF_PRIVATE | DTF_PROTECTED, DT_TYPE_STRUCT, ptempl);
		break;
	case TK_UNION:
		dec = ParseStructDeclaration(flags, DT_TYPE_UNION, ptempl);
		break;
	default:
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Declaration starts with invalid token", TokenNames[mScanner->mToken]);
		mScanner->NextToken();
	}

	if (!dec)
	{
		dec = new Declaration(mScanner->mLocation, DT_TYPE_VOID);
		dec->mSize = 0;
		dec->mFlags |= DTF_DEFINED;
	}

	if (mScanner->mToken == TK_CONST)
	{
		dec = dec->ToConstType();
		mScanner->NextToken();
	}

	return dec;

}

Declaration* Parser::ParsePostfixDeclaration(void)
{
	Declaration* dec;

	if (mScanner->mToken == TK_MUL)
	{
		mScanner->NextToken();

		Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
		ndec->mSize = 2;
		ndec->mFlags |= DTF_DEFINED;
		ndec->mCompilerOptions = mCompilerOptions;

		for (;;)
		{
			if (mScanner->mToken == TK_CONST)
			{
				ndec->mFlags |= DTF_CONST;
				mScanner->NextToken();
			}
			else if (mScanner->mToken == TK_VOLATILE)
			{
				ndec->mFlags |= DTF_VOLATILE;
				mScanner->NextToken();
			}
			else
				break;
		}

		Declaration* dec = ParsePostfixDeclaration();
		ndec->mBase = dec;
		return ndec;
	}
	else if (mScanner->mToken == TK_BINARY_AND && (mCompilerOptions & COPT_CPLUSPLUS))
	{
		mScanner->NextToken();

		Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE);
		ndec->mSize = 2;
		ndec->mFlags |= DTF_DEFINED;

		for (;;)
		{
			if (mScanner->mToken == TK_CONST)
			{
				ndec->mFlags |= DTF_CONST;
				mScanner->NextToken();
			}
			else if (mScanner->mToken == TK_VOLATILE)
			{
				ndec->mFlags |= DTF_VOLATILE;
				mScanner->NextToken();
			}
			else
				break;
		}

		Declaration* dec = ParsePostfixDeclaration();
		ndec->mBase = dec;
		return ndec;
	}
	else if (mScanner->mToken == TK_LOGICAL_AND && (mCompilerOptions & COPT_CPLUSPLUS))
	{
		mScanner->NextToken();

		Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_RVALUEREF);
		ndec->mSize = 2;
		ndec->mFlags |= DTF_DEFINED;

		for (;;)
		{
			if (mScanner->mToken == TK_CONST)
			{
				ndec->mFlags |= DTF_CONST;
				mScanner->NextToken();
			}
			else if (mScanner->mToken == TK_VOLATILE)
			{
				ndec->mFlags |= DTF_VOLATILE;
				mScanner->NextToken();
			}
			else
				break;
		}

		Declaration* dec = ParsePostfixDeclaration();
		ndec->mBase = dec;
		return ndec;
	}
	else if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
	{
		Declaration* vdec = ParsePostfixDeclaration();
		if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
			mScanner->NextToken();
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected");
		dec = vdec;
	}
	else if (ConsumeTokenIf(TK_ELLIPSIS))
	{
		if (mScanner->mToken == TK_IDENT)
		{
			dec = new Declaration(mScanner->mLocation, DT_PACK_VARIABLE);
			dec->mIdent = mScanner->mTokenIdent;
			dec->mSection = mBSSection;
			dec->mBase = nullptr;
			mScanner->NextToken();
		}
		else
		{
			dec = new Declaration(mScanner->mLocation, DT_PACK_ANON);
			dec->mIdent = mScanner->mTokenIdent;
			dec->mBase = nullptr;
		}
	}
	else if (mScanner->mToken == TK_IDENT)
	{
		dec = new Declaration(mScanner->mLocation, DT_VARIABLE);
		dec->mIdent = mScanner->mTokenIdent;
		dec->mSection = mBSSection;
		dec->mBase = nullptr;
		mScanner->NextToken();

		if (mScanner->mToken == TK_LESS_THAN && mTemplateScope)
		{
			Declaration* tdec = mScope->Lookup(dec->mIdent);
			if (tdec && tdec->mTemplate)
			{
				// for now just skip over template stuff
				while (!ConsumeTokenIf(TK_GREATER_THAN))
					mScanner->NextToken();

				if (mTemplateScope->mParent)
				{
					if (mTemplateScope->mParent->mName)
						dec->mIdent = dec->mIdent->Mangle(mTemplateScope->mParent->mName->mString);
				}
				else if (mTemplateScope->mName)
					dec->mIdent = dec->mIdent->Mangle(mTemplateScope->mName->mString);
			}
		}

		dec->mQualIdent = mScope->Mangle(dec->mIdent);

		if (mScanner->mToken == TK_OPEN_PARENTHESIS && mScope->mLevel >= SLEVEL_FUNCTION)
		{
			// Can't be a function declaration in local context, so it must be an object
			// declaration with initializer, so return immediately

			return dec;
		}

		while (ConsumeTokenIf(TK_COLCOLON))
		{
			if (mScanner->mToken == TK_IDENT)
			{
				dec->mIdent = mScanner->mTokenIdent;

				char	buffer[200];
				strcpy_s(buffer, dec->mQualIdent->mString);
				strcat_s(buffer, "::");
				strcat_s(buffer, dec->mIdent->mString);
				dec->mQualIdent = Ident::Unique(buffer);

				mScanner->NextToken();
			}
		}
	}
	else
	{
		dec = new Declaration(mScanner->mLocation, DT_ANON);
		dec->mBase = nullptr;
	}

	for (;;)
	{
		if (mScanner->mToken == TK_OPEN_BRACKET)
		{
			Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_ARRAY);
			ndec->mSize = 0;
			ndec->mFlags = 0;
			mScanner->NextToken();
			if (mScanner->mToken != TK_CLOSE_BRACKET)
			{
				Expression* exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType())
				{
					if (exp->mDecValue->mType == DT_CONST_INTEGER)
						ndec->mSize = int(exp->mDecValue->mInteger);
					else if (exp->mDecValue->mType == DT_CONST_TEMPLATE)
					{
						ndec->mSize = 0;
						ndec->mTemplate = exp->mDecValue;
					}
					else
						mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Constant integer expression expected");
				}
				else
					mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Constant integer expression expected");
				ndec->mFlags |= DTF_DEFINED;
			}
			if (mScanner->mToken == TK_CLOSE_BRACKET)
				mScanner->NextToken();
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "']' expected");
			ndec->mBase = dec;
			dec = ndec;
		}
		else if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
		{
			if (mScanner->mToken == TK_CLOSE_PARENTHESIS || mScanner->mToken == TK_ELLIPSIS || IsTypeToken())
			{
				mScanner->UngetToken(TK_OPEN_PARENTHESIS);
				dec = ParseFunctionDeclaration(dec);
			}
			else
			{
				mScanner->UngetToken(TK_OPEN_PARENTHESIS);
				return dec;
			}
		}
		else
			return dec;
	}
}

Declaration * Parser::ParseFunctionDeclaration(Declaration* bdec)
{
	Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
	ndec->mSize = 0;
	Declaration* pdec = nullptr;
	mScanner->NextToken();
	if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
	{
		int	vi = 0;
		for (;;)
		{
			if (mScanner->mToken == TK_ELLIPSIS)
			{
				ndec->mFlags |= DTF_VARIADIC;
				mScanner->NextToken();
				break;
			}

			Declaration* bdec = ParseBaseTypeDeclaration(0, true);
//			if (bdec->mType == DT_PACK_TEMPLATE)
//				ConsumeToken(TK_ELLIPSIS);

			Declaration* adec = ParsePostfixDeclaration();
			adec = ReverseDeclaration(adec, bdec);

			if (adec->mBase->mType == DT_TYPE_VOID)
			{
				if (pdec)
					mErrors->Error(pdec->mLocation, EERR_WRONG_PARAMETER, "Invalid void argument");
				break;
			}
			else
			{
				if (adec->mType != DT_PACK_VARIABLE && !(adec->mBase->mFlags & DTF_DEFINED) && adec->mBase->mType != DT_TYPE_ARRAY && !adec->mBase->mTemplate)
					mErrors->Error(adec->mLocation, EERR_UNDEFINED_OBJECT, "Type of argument not defined");

				if (adec->mType == DT_PACK_VARIABLE || adec->mType == DT_PACK_ANON)
				{
					adec->mType = DT_PACK_ARGUMENT;
					if (adec->mBase)
					{
						ndec->mParamPack = adec;

						Declaration* atdec = adec->mBase;
						
						if (atdec->IsReference())
							atdec = atdec->mBase;
						if (atdec->mType == DT_PACK_TYPE)
						{
							atdec = atdec->mParams;

							Declaration* apdec = adec;
							while (atdec)
							{
								apdec = new Declaration(adec->mLocation, DT_ARGUMENT);
								if (!adec->mParams)
									adec->mParams = apdec;

								if (adec->mBase->IsReference())
								{
									if (adec->mBase->mBase->mFlags & DTF_CONST)
										apdec->mBase = atdec->ToConstType()->BuildReference(adec->mLocation, adec->mBase->mType);
									else
										apdec->mBase = atdec->BuildReference(adec->mLocation, adec->mBase->mType);
								}
								else
									apdec->mBase = atdec;

								atdec = atdec->mNext;
								apdec->mFlags = DTF_DEFINED;
								apdec->mVarIndex = vi;
								apdec->mOffset = 0;

								if (apdec->mBase->mType == DT_TYPE_ARRAY)
								{
									Declaration* ndec = new Declaration(apdec->mBase->mLocation, DT_TYPE_POINTER);
									ndec->mBase = apdec->mBase->mBase;
									ndec->mSize = 2;
									ndec->mFlags |= DTF_DEFINED;
									apdec->mBase = ndec;
								}

								apdec->mSize = apdec->mBase->mSize;

								vi += apdec->mSize;
								if (pdec)
									pdec->mNext = apdec;
								else
									ndec->mParams = apdec;
								pdec = apdec;
							}
						}
						else
						{
							if (pdec)
								pdec->mNext = adec;
							else
								ndec->mParams = adec;
							pdec = adec;
						}
					}
				}
				else
				{
					adec->mType = DT_ARGUMENT;
					adec->mVarIndex = vi;
					adec->mOffset = 0;
					if (adec->mBase->mType == DT_TYPE_ARRAY && !adec->mBase->mTemplate)
					{
						Declaration* ndec = new Declaration(adec->mBase->mLocation, DT_TYPE_POINTER);
						ndec->mBase = adec->mBase->mBase;
						ndec->mSize = 2;
						ndec->mFlags |= DTF_DEFINED;
						adec->mBase = ndec;
					}

					adec->mSize = adec->mBase->mSize;

					if (((mCompilerOptions & COPT_CPLUSPLUS) || !(mCompilerOptions & COPT_STRICT)) && ConsumeTokenIf(TK_ASSIGN))
					{
						adec->mValue = ParseExpression(false);
					}

					vi += adec->mSize;
					if (pdec)
						pdec->mNext = adec;
					else
						ndec->mParams = adec;
					pdec = adec;
				}

				if (mScanner->mToken == TK_COMMA)
					mScanner->NextToken();
				else
					break;
			}
		}

		if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
			mScanner->NextToken();
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected");
	}
	else
		mScanner->NextToken();
	ndec->mBase = bdec;
	ndec->mFlags |= DTF_DEFINED;

	return ndec;
}

Declaration* Parser::ReverseDeclaration(Declaration* odec, Declaration* bdec)
{
	Declaration* cdec = odec->mBase;

	if (bdec)
	{
		if (odec->mType == DT_TYPE_ARRAY)
		{
			odec->mSize *= bdec->mSize;
			odec->mFlags |= bdec->mFlags & DTF_CONST;
		}
		else if (odec->mType == DT_VARIABLE || odec->mType == DT_ARGUMENT || odec->mType == DT_ANON)
			odec->mSize = bdec->mSize;
		odec->mBase = bdec;
	}

	if (cdec)
		return ReverseDeclaration(cdec, odec);
	else
		return odec;
}

Declaration * Parser::CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp)
{
	exp = exp->ConstantDereference(mErrors, mDataSection);

	exp = CoerceExpression(exp, dtype);

	exp = exp->ConstantFold(mErrors, mDataSection);

	Declaration* dec = exp->mDecValue;

	if (exp->mType == EX_CONSTANT)
	{
		if (!dtype->CanAssign(exp->mDecType))
		{
			mErrors->Error(exp->mLocation, EERR_CONSTANT_INITIALIZER, "Incompatible constant initializer");
		}
		else
		{
			if (dec->mType == DT_CONST_FLOAT)
			{
				if (dtype->IsIntegerType() || dtype->mType == DT_TYPE_POINTER)
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_INTEGER);
					ndec->mInteger = int(dec->mNumber);
					ndec->mBase = dtype;
					dec = ndec;
				}
				else
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_FLOAT);
					ndec->mNumber = dec->mNumber;
					ndec->mBase = dtype;
					dec = ndec;
				}
			}
			else if (dec->mType == DT_CONST_INTEGER)
			{
				if (dtype->mType == DT_TYPE_FLOAT)
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_FLOAT);
					ndec->mNumber = double(dec->mInteger);
					ndec->mBase = dtype;
					dec = ndec;
				}
				else
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_INTEGER);
					ndec->mInteger = dec->mInteger;
					ndec->mBase = dtype;
					dec = ndec;
				}
			}
			else if (dec->mType == DT_CONST_DATA)
			{
				if (dtype->mType == DT_TYPE_POINTER)
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_POINTER);
					ndec->mValue = exp;
					ndec->mBase = dtype;
					dec = ndec;
				}
				else
				{
					Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_DATA);
					ndec->mSection = dec->mSection;
					ndec->mData = dec->mData;
					ndec->mSize = dec->mSize;
					ndec->mBase = dtype;
					dec = ndec;
				}
			}
			else if (dec->mType == DT_CONST_ADDRESS)
			{
				Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_ADDRESS);
				ndec->mInteger = dec->mInteger;
				ndec->mBase = dtype;
				dec = ndec;
			}

			dec->mOffset = offset;
		}
	}
	else if (!dec && exp->mType == EX_CONSTRUCT)
	{
		dec = new Declaration(exp->mLocation, DT_CONST_CONSTRUCTOR);
		dec->mValue = exp;
		dec->mBase = exp->mDecType;
		dec->mOffset = offset;
	}
	else if (dec && dtype->mType == DT_TYPE_POINTER && (dec->mType == DT_VARIABLE || dec->mType == DT_VARIABLE_REF) && exp->mDecType->mType == DT_TYPE_ARRAY && (dec->mFlags & DTF_GLOBAL))
	{
		if (dtype->CanAssign(exp->mDecType))
		{
			Declaration	*	ndec = new Declaration(dec->mLocation, DT_CONST_POINTER);
			ndec->mValue = exp;
			ndec->mBase = dtype;
			dec = ndec;
			dec->mOffset = offset;
		}
		else
		{
			dtype->CanAssign(exp->mDecType);
			mErrors->Error(exp->mLocation, EERR_CONSTANT_INITIALIZER, "Incompatible constant initializer");
		}
	}
	else
		mErrors->Error(exp->mLocation, EERR_CONSTANT_INITIALIZER, "Constant initializer expected");

	return dec;
}

uint8* Parser::ParseStringLiteral(int & msize)
{
	int	size = mScanner->mTokenStringSize;
	if (size + 1 > msize)
		msize = size + 1;
	uint8* d = new uint8[msize];

	int i = 0;
	while (i < size)
	{
		d[i] = mCharMap[mScanner->mTokenString[i]];
		i++;
	}

	mScanner->NextToken();

	while (mScanner->mToken == TK_PREP_PRAGMA)
	{
		mScanner->NextToken();
		ParsePragma();
	}

	// automatic string concatenation
	while (mScanner->mToken == TK_STRING)
	{
		int	s = mScanner->mTokenStringSize;

		if (size + s + 1 > msize)
			msize = size + s + 1;

		uint8* nd = new uint8[msize];
		memcpy(nd, d, size);
		int i = 0;
		while (i < s)
		{
			nd[i + size] = mCharMap[mScanner->mTokenString[i]];
			i++;
		}
		size += s;
		delete[] d;
		d = nd;
		mScanner->NextToken();

		while (mScanner->mToken == TK_PREP_PRAGMA)
		{
			mScanner->NextToken();
			ParsePragma();
		}
	}

	while (size < msize)
		d[size++] = 0;

	return d;
}

Expression* Parser::DefaultInitExpression(Expression* vexp)
{
	Expression* exp = nullptr;
	Declaration* dtype = vexp->mDecType;

	if (dtype->mType == DT_TYPE_INTEGER)
	{
		Expression* rexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		rexp->mDecValue = TheZeroIntegerConstDeclaration;
		rexp->mDecType = dtype;

		exp = new Expression(rexp->mLocation, EX_INITIALIZATION);
		exp->mToken = TK_ASSIGN;
		exp->mLeft = vexp;
		exp->mRight = rexp;
		exp->mDecType = dtype;
	}
	else
	{
		mErrors->Error(mScanner->mLocation, EERR_INVALID_INITIALIZER, "Invalid initializer");
		exp = new Expression(mScanner->mLocation, EX_VOID);
	}

	return exp;
}

Expression* Parser::CloneVarInitExpression(Expression* vexp, Expression* iexp, Expression* qexp)
{
	if (!iexp)
		return nullptr;
	else if (iexp == qexp)
		return vexp;
	else
	{
		Expression* nexp = new Expression(iexp->mLocation, iexp->mType);
		nexp->mToken = iexp->mToken;
		nexp->mConst = iexp->mConst;
		nexp->mDecType = iexp->mDecType;
		nexp->mDecValue = iexp->mDecValue;
		nexp->mLeft = CloneVarInitExpression(vexp, iexp->mLeft, qexp);
		nexp->mRight = CloneVarInitExpression(vexp, iexp->mRight, qexp);
		return nexp;
	}
}

Expression * Parser::CopyElision(Expression* vexp, Expression* rexp)
{
	if (rexp->mType == EX_CONSTRUCT && rexp->mRight->mType == EX_VARIABLE && (rexp->mRight->mDecValue->mFlags & DTF_TEMPORARY) && vexp->mType == EX_VARIABLE)
	{
		rexp->ReplaceVariable(rexp->mRight->mDecValue, vexp->mDecValue);

		return rexp;
	}
	else if (rexp->mType == EX_CALL)
	{
		Expression* iexp = new Expression(rexp->mLocation, EX_INITIALIZATION);
		iexp->mToken = TK_ASSIGN;
		iexp->mLeft = vexp;
		iexp->mRight = rexp;
		iexp->mDecType = vexp->mDecType;

		Expression* dexp = nullptr;
		if (vexp->mDecType->mDestructor)
		{
			Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
			texp->mToken = TK_BINARY_AND;
			texp->mLeft = vexp;
			texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
			texp->mDecType->mBase = vexp->mDecType->ToMutableType();
			texp->mDecType->mSize = 2;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = vexp->mDecType->mDestructor;
			cexp->mDecType = cexp->mDecValue->mBase;

			dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = texp;
		}

		Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

		nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
		nexp->mLeft->mLeft = iexp;
		nexp->mLeft->mRight = dexp;

		nexp->mRight = vexp;
		nexp->mDecType = vexp->mDecType;

		return nexp;
	}


	return nullptr;
}

Expression* Parser::ParseVarInitExpression(Expression* vexp, bool inner)
{
	Expression* exp = nullptr;
	Declaration* dtype = vexp->mDecType;

	if (dtype->mType == DT_TYPE_ARRAY && mScanner->mToken == TK_STRING && dtype->mBase->mType == DT_TYPE_INTEGER && dtype->mBase->mSize == 1)
	{
		int ds = dtype->mSize;
		uint8* d = ParseStringLiteral(ds);

		if (!(dtype->mFlags & DTF_DEFINED))
		{
			dtype->mFlags |= DTF_DEFINED;
			dtype->mSize = int(ds);
		}

		Declaration * dec = new Declaration(mScanner->mLocation, DT_CONST_DATA);
		dec->mBase = dtype;
		dec->mSize = dtype->mSize;
		dec->mSection = mCodeSection;

		dec->mData = d;

		Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		cexp->mDecValue = dec;
		cexp->mDecType = dtype;

		exp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
		exp->mToken = TK_ASSIGN;
		exp->mLeft = vexp;
		exp->mRight = cexp;
		exp->mDecType = dtype;

		if (ds > dtype->mSize + 1)
			mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "String constant is too large for char array");
	}
	else if ((dtype->mType == DT_TYPE_STRUCT || dtype->mType == DT_TYPE_UNION) && ConsumeTokenIf(TK_OPEN_BRACE))
	{
		NumberSet	fset(dtype->mSize);

		bool	isconst = true;
		Declaration* edec = dtype->mParams;
		for(;;)
		{
			if (ConsumeTokenIf(TK_DOT))
			{
				if (mScanner->mToken == TK_IDENT)
				{
					Declaration	*	ttype = dtype;

					Declaration* ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE);
					while (!ndec && ttype->mBase)
					{
						ttype = ttype->mBase->mBase;
						ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE);
					}

					if (ndec)
						edec = ndec;
					else
						mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Struct member not found", mScanner->mTokenIdent);

					mScanner->NextToken();
					ConsumeToken(TK_ASSIGN);
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Identifier expected");
			}

			if (!edec)
				break;

			fset += edec->mOffset;

			Expression* qexp = new Expression(mScanner->mLocation, EX_QUALIFY);
			qexp->mLeft = vexp;
			qexp->mDecValue = edec;
			qexp->mDecType = edec->mBase;

			Expression* nexp = ParseVarInitExpression(qexp);
			if (nexp->mType != EX_INITIALIZATION || nexp->mRight->mType != EX_CONSTANT)
				isconst = false;

			exp = nexp->ListAppend(exp);

			if (dtype->mType == DT_TYPE_UNION)
				break;

			edec = edec->mNext;

			if (!ConsumeTokenIf(TK_COMMA))
				break;
		}
		ConsumeToken(TK_CLOSE_BRACE);

		if (isconst)
		{
			Declaration * csdec = new Declaration(mScanner->mLocation, DT_CONST_STRUCT);
			csdec->mBase = dtype;
			csdec->mSize = dtype->mSize;
			csdec->mSection = mCodeSection;

			Declaration* last = nullptr;

			Expression* lexp = exp;
			while (lexp)
			{
				Expression* rexp;
				if (lexp->mType == EX_LIST)
				{
					rexp = lexp->mRight;
					lexp = lexp->mLeft;
				}
				else
				{
					rexp = lexp;
					lexp = nullptr;
				}

				Declaration* cidec = CopyConstantInitializer(rexp->mLeft->mDecValue->mOffset, rexp->mDecType, rexp->mRight);
				if (cidec)
				{
					cidec->mBits = rexp->mLeft->mDecValue->mBits;
					cidec->mShift = rexp->mLeft->mDecValue->mShift;
				}

				if (last)
					last->mNext = cidec;
				else
					csdec->mParams = cidec;
				last = cidec;
			}

			if (exp)
			{
				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = csdec;
				cexp->mDecType = dtype;

				exp = new Expression(exp->mLocation, EX_INITIALIZATION);
				exp->mToken = TK_ASSIGN;
				exp->mLeft = vexp;
				exp->mRight = cexp;
			}
		}
		else if (dtype->mType == DT_TYPE_STRUCT)
		{
			edec = dtype->mParams;
			while (edec)
			{
				if (!fset[edec->mOffset])
				{
					fset += edec->mOffset;

					Expression* qexp = new Expression(mScanner->mLocation, EX_QUALIFY);
					qexp->mLeft = vexp;
					qexp->mDecValue = edec;
					qexp->mDecType = edec->mBase;

					Expression* nexp = DefaultInitExpression(qexp);
					exp = nexp->ListAppend(exp);
				}

				edec = edec->mNext;
			}
		}

		if (exp)
			exp->mDecType = dtype;
	}
	else if (dtype->mType == DT_TYPE_ARRAY && (inner || ConsumeTokenIf(TK_OPEN_BRACE)))
	{
		if (inner && ConsumeTokenIf(TK_OPEN_BRACE))
			inner = false;

		int	index = 0, stride = dtype->mBase->mSize, size = dtype->mSize / stride, mindex = 0;

		if (!(dtype->mFlags & DTF_DEFINED))
			size = 0x10000;

		NumberSet	fset(size);
		bool	isconst = true;

		for (;;)
		{
			int	nrep = 1;

			if (ConsumeTokenIf(TK_OPEN_BRACKET))
			{
				Expression* istart = ParseRExpression();
				if (istart->mType != EX_CONSTANT || istart->mDecValue->mType != DT_CONST_INTEGER)
					mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant index expected");
				else
				{
					index = int(istart->mDecValue->mInteger);
					if (index >= size)
						mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant initializer out of range");

					if (ConsumeTokenIf(TK_ELLIPSIS))
					{
						Expression* iend = ParseRExpression();
						if (iend->mType != EX_CONSTANT || iend->mDecValue->mType != DT_CONST_INTEGER)
							mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant index expected");
						else
						{
							nrep = int(iend->mDecValue->mInteger - istart->mDecValue->mInteger + 1);

							if (size + nrep > dtype->mSize)
								mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant initializer out of range");
						}
					}
				}

				ConsumeToken(TK_CLOSE_BRACKET);
				ConsumeToken(TK_ASSIGN);
			}

			if (index > mindex)
				mindex = index;
			if (index < size)
				fset += index;

			Expression* qexp = new Expression(mScanner->mLocation, EX_INDEX);
			qexp->mLeft = vexp;
			qexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
			qexp->mRight->mDecType = TheUnsignedIntTypeDeclaration;
			qexp->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
			qexp->mRight->mDecValue->mSize = 2;
			qexp->mRight->mDecValue->mInteger = index;
			qexp->mRight->mDecValue->mBase = TheUnsignedIntTypeDeclaration;
			qexp->mDecType = dtype->mBase;

			Expression* nexp = ParseVarInitExpression(qexp, true);
			if (nexp->mType != EX_INITIALIZATION || nexp->mRight->mType != EX_CONSTANT)
				isconst = false;
			if (nexp->mRight->mType == EX_PACK)
			{
				ConsumeToken(TK_ELLIPSIS);
				Declaration* pdec = nexp->mRight->mDecValue->mParams;
				nexp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE);
				nexp->mRight->mDecType = pdec->mBase;
				nexp->mRight->mDecValue = pdec;
				exp = nexp->ListAppend(exp);
			
				pdec = pdec->mNext;
				while (pdec)
				{
					index++;

					if (index > mindex)
						mindex = index;
					if (index < size)
						fset += index;

					Expression* qexp = new Expression(mScanner->mLocation, EX_INDEX);
					qexp->mLeft = vexp;
					qexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
					qexp->mRight->mDecType = TheUnsignedIntTypeDeclaration;
					qexp->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
					qexp->mRight->mDecValue->mSize = 2;
					qexp->mRight->mDecValue->mInteger = index;
					qexp->mRight->mDecValue->mBase = TheUnsignedIntTypeDeclaration;
					qexp->mDecType = dtype->mBase;

					nexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
					nexp->mToken = TK_ASSIGN;
					nexp->mLeft = qexp;
					nexp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE);
					nexp->mRight->mDecType = pdec->mBase;
					nexp->mRight->mDecValue = pdec;
					nexp->mDecType = dtype->mBase;

					exp = nexp->ListAppend(exp);
					pdec = pdec->mNext;
				}
			}
			else
				exp = nexp->ListAppend(exp);

			index++;

			for (int i = 1; i < nrep; i++)
			{
				if (index > mindex)
					mindex = index;
				if (index < size)
					fset += index;

				Expression* rqexp = new Expression(mScanner->mLocation, EX_INDEX);
				rqexp->mLeft = vexp;
				rqexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
				rqexp->mRight->mDecType = TheUnsignedIntTypeDeclaration;
				rqexp->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
				rqexp->mRight->mDecValue->mSize = 2;
				rqexp->mRight->mDecValue->mInteger = index;
				rqexp->mRight->mDecValue->mBase = TheUnsignedIntTypeDeclaration;
				rqexp->mDecType = dtype->mBase;

				Expression* rnexp = CloneVarInitExpression(rqexp, nexp, qexp);
				exp = rnexp->ListAppend(exp);

				index++;
			}

			if (inner && index >= size)
				break;
			if (!ConsumeTokenIf(TK_COMMA))
				break;
			if (inner && mScanner->mToken == TK_OPEN_BRACKET)
			{
				mScanner->UngetToken(TK_COMMA);
				break;
			}
			if (mScanner->mToken == TK_CLOSE_BRACE)
				break;
		}

		if (!inner)
		{
			ConsumeTokenIf(TK_COMMA);
			ConsumeToken(TK_CLOSE_BRACE);
		}


		if (!(dtype->mFlags & DTF_DEFINED))
		{
			size = mindex + 1;
			dtype->mSize = size * dtype->mBase->mSize;
			dtype->mFlags |= DTF_DEFINED;
		}

		if (isconst)
		{
			Declaration* csdec = new Declaration(mScanner->mLocation, DT_CONST_STRUCT);
			csdec->mBase = dtype;
			csdec->mSize = dtype->mSize;
			csdec->mSection = mDataSection;

			Declaration* last = nullptr;

			Expression* lexp = exp;
			while (lexp)
			{
				Expression* rexp;
				if (lexp->mType == EX_LIST)
				{
					rexp = lexp->mRight;
					lexp = lexp->mLeft;
				}
				else
				{
					rexp = lexp;
					lexp = nullptr;
				}

				Declaration* cidec = CopyConstantInitializer(int(rexp->mLeft->mRight->mDecValue->mInteger) * dtype->Stride(), rexp->mDecType, rexp->mRight);

				if (last)
					last->mNext = cidec;
				else
					csdec->mParams = cidec;
				last = cidec;
			}

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = csdec;
			cexp->mDecType = dtype;

			exp = new Expression(exp->mLocation, EX_INITIALIZATION);
			exp->mToken = TK_ASSIGN;
			exp->mLeft = vexp;
			exp->mRight = cexp;
		}
		else
		{
			for (int i = 0; i < size; i++)
			{
				if (!fset[i])
				{
					fset += i;

					Expression* qexp = new Expression(mScanner->mLocation, EX_INDEX);
					qexp->mLeft = vexp;
					qexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
					qexp->mRight->mDecType = TheUnsignedIntTypeDeclaration;
					qexp->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
					qexp->mRight->mDecValue->mSize = 2;
					qexp->mRight->mDecValue->mInteger = i;
					qexp->mRight->mDecValue->mBase = TheUnsignedIntTypeDeclaration;
					qexp->mDecType = dtype->mBase;

					Expression* nexp = DefaultInitExpression(qexp);
					exp = nexp->ListAppend(exp);
				}
			}
		}

		exp->mDecType = dtype;
	}
	else if (dtype->mType == DT_TYPE_AUTO || dtype->mType == DT_TYPE_REFERENCE)
	{
		exp = ParseRExpression();
	}
	else if (dtype->mDefaultConstructor)
	{
		Declaration* fcons = dtype->mScope ? dtype->mScope->Lookup(dtype->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;

		if (dtype->mFlags & DTF_PURE_VIRTUAL)
			mErrors->Error(mScanner->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", dtype->mIdent);

		Declaration* mtype = dtype->ToMutableType();

		Expression* rexp = ParseRExpression();
		if (rexp->mDecType->IsSame(dtype))
		{
			exp = CopyElision(vexp, rexp);
			fcons = dtype->mCopyConstructor;
		}

		if (!exp)
		{
			if (fcons)
			{
				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = fcons;
				cexp->mDecType = cexp->mDecValue->mBase;

				Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
				fexp->mLeft = cexp;
				fexp->mRight = rexp;

				Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
				texp->mToken = TK_BINARY_AND;
				texp->mLeft = vexp;
				texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
				texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
				texp->mDecType->mBase = mtype;
				texp->mDecType->mSize = 2;

				if (fexp->mRight)
				{
					Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
					lexp->mLeft = texp;
					lexp->mRight = fexp->mRight;
					fexp->mRight = lexp;
				}
				else
					fexp->mRight = texp;

				fexp = ResolveOverloadCall(fexp);

				Expression* dexp = nullptr;
				if (dtype->mDestructor)
				{
					Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					cexp->mDecValue = dtype->mDestructor;
					cexp->mDecType = cexp->mDecValue->mBase;

					dexp = new Expression(mScanner->mLocation, EX_CALL);
					dexp->mLeft = cexp;
					dexp->mRight = texp;
				}

				Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

				nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
				nexp->mLeft->mLeft = fexp;
				nexp->mLeft->mRight = dexp;

				nexp->mRight = vexp;
				nexp->mDecType = vexp->mDecType;

				exp = nexp;
			}
			else
			{
				rexp = CoerceExpression(rexp, dtype);
				exp = new Expression(rexp->mLocation, EX_INITIALIZATION);
				exp->mToken = TK_ASSIGN;
				exp->mLeft = vexp;
				exp->mRight = rexp;
				exp->mDecType = dtype;
			}
		}
	}
	else		
	{		
		Expression* rexp = ParseRExpression();
		rexp = CoerceExpression(rexp, dtype);
		exp = new Expression(rexp->mLocation, EX_INITIALIZATION);
		exp->mToken = TK_ASSIGN;
		exp->mLeft = vexp;
		exp->mRight = rexp;
		exp->mDecType = dtype;
	}

	return exp;
}

Expression* Parser::ParseConstInitExpression(Declaration* dtype, bool inner)
{
	Expression* exp = nullptr;
	Declaration* dec;

	if (dtype->mType == DT_TYPE_AUTO)
	{
		exp = ParseRExpression();
	}
	else if (dtype->mType == DT_TYPE_ARRAY || dtype->mType == DT_TYPE_STRUCT || dtype->mType == DT_TYPE_UNION)
	{
		if (dtype->mType != DT_TYPE_ARRAY && !(dtype->mFlags & DTF_DEFINED))
		{
			if (dtype->mIdent)
				mErrors->Error(mScanner->mLocation, EERR_UNDEFINED_OBJECT, "Constant for undefined type", dtype->mIdent);
			else
				mErrors->Error(mScanner->mLocation, EERR_UNDEFINED_OBJECT, "Constant for undefined anonymous type");
		}

		if (mScanner->mToken == TK_STRING && dtype->mType == DT_TYPE_ARRAY && dtype->mBase->mType == DT_TYPE_INTEGER && dtype->mBase->mSize == 1)
		{
			int ds = dtype->mSize;
			uint8* d = ParseStringLiteral(ds);

			if (!(dtype->mFlags & DTF_DEFINED))
			{
				dtype->mFlags |= DTF_DEFINED;
				dtype->mSize = int(ds);
			}

			dec = new Declaration(mScanner->mLocation, DT_CONST_DATA);
			dec->mBase = dtype;
			dec->mSize = dtype->mSize;
			dec->mSection = mDataSection;

			dec->mData = d;

			if (ds > dtype->mSize + 1)
				mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "String constant is too large for char array");
		}
		else if ((inner && !dtype->mDefaultConstructor) || ConsumeTokenIf(TK_OPEN_BRACE))
		{
			if (inner && ConsumeTokenIf(TK_OPEN_BRACE))
				inner = false;

			dec = new Declaration(mScanner->mLocation, DT_CONST_STRUCT);
			dec->mBase = dtype;
			dec->mSize = dtype->mSize;
			dec->mSection = mDataSection;

			Declaration* last = nullptr;

			if (dtype->mType == DT_TYPE_ARRAY)
			{
				int	index = 0, stride = dtype->Stride(), size = 0;

				if (dtype->mFlags & DTF_STRIPED)
					dec->mStripe = dtype->mBase->mStripe;

				while (!(dtype->mFlags & DTF_DEFINED) || size < dtype->mSize)
				{
					int	nrep = 1;

					if (ConsumeTokenIf(TK_OPEN_BRACKET))
					{
						Expression* istart = ParseRExpression();
						if (istart->mType != EX_CONSTANT || istart->mDecValue->mType != DT_CONST_INTEGER)
							mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant index expected");
						else
						{
							index = stride * int(istart->mDecValue->mInteger);
							if (index >= dtype->mSize)
							{
								mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant initializer out of range");
								break;
							}

							if (ConsumeTokenIf(TK_ELLIPSIS))
							{
								Expression* iend = ParseRExpression();
								if (iend->mType != EX_CONSTANT || iend->mDecValue->mType != DT_CONST_INTEGER)
									mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant index expected");
								else
								{
									nrep = int(iend->mDecValue->mInteger - istart->mDecValue->mInteger + 1);

									if (size + nrep * dtype->mBase->mSize > dtype->mSize)
									{
										mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Constant initializer out of range");
										break;
									}
								}
							}
						}

						ConsumeToken(TK_CLOSE_BRACKET);
						ConsumeToken(TK_ASSIGN);
					}

					Expression* texp = ParseConstInitExpression(dtype->mBase, true);
					texp = texp->ConstantFold(mErrors, mDataSection);
					for (int i = 0; i < nrep; i++)
					{
						Declaration* cdec = CopyConstantInitializer(index, dtype->mBase, texp);

						if (last)
							last->mNext = cdec;
						else
							dec->mParams = cdec;
						last = cdec;

						index += stride;
						size += dtype->mBase->mSize;
					}

					if (inner && (dtype->mFlags & DTF_DEFINED) && size >= dtype->mSize)
						break;
					if (!ConsumeTokenIf(TK_COMMA))
						break;
					if (inner && mScanner->mToken == TK_OPEN_BRACKET)
					{
						mScanner->UngetToken(TK_COMMA);
						break;
					}
					if (mScanner->mToken == TK_CLOSE_BRACE)
						break;
				}

				if (!(dtype->mFlags & DTF_DEFINED))
				{
					dtype->mFlags |= DTF_DEFINED;
					dtype->mSize = size;
					dec->mSize = size;
				}
			}
			else
			{
				ExpandingArray<Declaration*>	path;

				Declaration* ttype = dtype;
				while (ttype->mBase)
				{
					path.Push(ttype);
					ttype = ttype->mBase->mBase;
				}

				Declaration* mdec = ttype->mParams;
				for(;;)
				{
					if (ConsumeTokenIf(TK_DOT))
					{
						if (mScanner->mToken == TK_IDENT)
						{
							ttype = dtype;

							path.SetSize(0);
							Declaration* ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE);
							while (!ndec && ttype->mBase)
							{
								path.Push(ttype);
								ttype = ttype->mBase->mBase;
								ndec = ttype->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_SCOPE);
							}

							if (ndec)
								mdec = ndec;
							else
								mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Struct member not found", mScanner->mTokenIdent);

							mScanner->NextToken();
							ConsumeToken(TK_ASSIGN);
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Identifier expected");
					}
					
					if (mdec)
					{
						Expression* texp = ParseConstInitExpression(mdec->mBase, true);

						Declaration* cdec = CopyConstantInitializer(mdec->mOffset, mdec->mBase, texp);
						if (cdec)
						{
							cdec->mBits = mdec->mBits;
							cdec->mShift = mdec->mShift;

							if (last)
								last->mNext = cdec;
							else
								dec->mParams = cdec;
							last = cdec;
						}

						mdec = mdec->mNext;
						while (!mdec && path.Size())
							mdec = path.Pop()->mParams;

						if (inner && !mdec)
							break;

						if (!ConsumeTokenIf(TK_COMMA))
							break;
					}
					else if (inner)
						break;
					else if (!ConsumeTokenIf(TK_COMMA))
						break;

					if (mScanner->mToken == TK_CLOSE_BRACE)
						break;
				}
			}

			if (!inner)
			{
				ConsumeTokenIf(TK_COMMA);
				ConsumeToken(TK_CLOSE_BRACE);
			}

			if (last)
				last->mNext = nullptr;
			else
				dec->mParams = nullptr;
		}
		else 
		{
			exp = ParseRExpression();
			return exp;
		}

		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecType = dtype;
		exp->mDecValue = dec;
	}
	else
	{
		exp = ParseRExpression();
		if (dtype->mType == DT_TYPE_POINTER && exp->mDecType && exp->mDecType->mType == DT_TYPE_ARRAY && exp->mType == EX_CONSTANT)
		{
			Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_POINTER);
			ndec->mBase = dtype;
			ndec->mValue = exp;
			dec = ndec;

			Expression	*	nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			nexp->mDecType = new Declaration(dec->mLocation, DT_TYPE_POINTER);
			nexp->mDecType->mBase = exp->mDecType->mBase;
			nexp->mDecType->mSize = 2;
			nexp->mDecType->mStride = exp->mDecType->mStride;
			nexp->mDecType->mFlags |= DTF_DEFINED;
			nexp->mDecValue = ndec;
			exp = nexp;
		}
		else if (exp->mType == EX_CONSTANT && exp->mDecType != dtype)
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			nexp->mDecType = dtype;

			if (dtype->mType == DT_TYPE_INTEGER || dtype->mType == DT_TYPE_ENUM || dtype->mType == DT_TYPE_BOOL)
			{
				Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_INTEGER);
				ndec->mBase = dtype;
				ndec->mSize = dtype->mSize;					

				if (exp->mDecValue->mType == DT_CONST_INTEGER)
					ndec->mInteger = exp->mDecValue->mInteger;
				else if (exp->mDecValue->mType == DT_CONST_FLOAT)
					ndec->mInteger = int64(exp->mDecValue->mNumber);
				else
					mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal integer constant initializer");

				nexp->mDecValue = ndec;
			}
			else if (dtype->mType == DT_TYPE_FLOAT)
			{
				Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_FLOAT);
				ndec->mBase = dtype;
				ndec->mSize = dtype->mSize;

				if (exp->mDecValue->mType == DT_CONST_INTEGER)
					ndec->mNumber = double(exp->mDecValue->mInteger);
				else if (exp->mDecValue->mType == DT_CONST_FLOAT)
					ndec->mNumber = exp->mDecValue->mNumber;
				else
					mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal float constant initializer");

				nexp->mDecValue = ndec;
			}
			else if (dtype->mType == DT_TYPE_POINTER)
			{
				if (exp->mDecValue->mType == DT_CONST_ADDRESS || exp->mDecValue->mType == DT_CONST_POINTER || exp->mDecValue->mType == DT_CONST_ASSEMBLER || exp->mDecValue->mType == DT_LABEL)
					;
				else if (exp->mDecValue->mType == DT_CONST_FUNCTION)
				{
					Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_POINTER);
					ndec->mBase = dtype;
					ndec->mValue = exp;
					dec = ndec;

					Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp->mDecType = new Declaration(dec->mLocation, DT_TYPE_POINTER);
					nexp->mDecType->mBase = exp->mDecType;
					nexp->mDecType->mSize = 2;
					nexp->mDecType->mFlags |= DTF_DEFINED;
					nexp->mDecValue = ndec;
					exp = nexp;
				}
				else if (exp->mDecValue->mType == DT_CONST_INTEGER && exp->mDecValue->mInteger == 0)
				{
					Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp->mDecValue = TheNullptrConstDeclaration;
					nexp->mDecType = TheNullPointerTypeDeclaration;
					exp = nexp;
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal pointer constant initializer");

				nexp = exp;
			}
			else
			{
				mErrors->Error(mScanner->mLocation, EERR_CONSTANT_INITIALIZER, "Illegal constant initializer");
				nexp = exp;
			}

			exp = nexp;
		}

	}

	return exp;
}

Expression* Parser::BuildMemberInitializer(Expression* vexp)
{
	Declaration* fcons = (vexp->mDecType->mType == DT_TYPE_STRUCT && vexp->mDecType->mScope) ? vexp->mDecType->mScope->Lookup(vexp->mDecType->mIdent->PreMangle("+")) : nullptr;

	if (fcons)
	{
		Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		cexp->mDecValue = fcons;
		cexp->mDecType = cexp->mDecValue->mBase;

		Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
		fexp->mLeft = cexp;

		mScanner->NextToken();
		if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
		{
			fexp->mRight = ParseListExpression(false, fcons->mBase->mParams->mNext);
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else
		{
			fexp->mRight = nullptr;
			mScanner->NextToken();
		}

		Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
		texp->mToken = TK_BINARY_AND;
		texp->mLeft = vexp;
		texp->mDecType = vexp->mDecType->BuildPointer(mScanner->mLocation);

		if (fexp->mRight)
		{
			Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
			lexp->mLeft = texp;
			lexp->mRight = fexp->mRight;
			fexp->mRight = lexp;
		}
		else
			fexp->mRight = texp;

		fexp = ResolveOverloadCall(fexp);

		return fexp;
	}
	else if (mScanner->mToken == TK_OPEN_BRACE)
	{
		return ParseVarInitExpression(vexp);
	}
	else
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
		nexp->mToken = TK_ASSIGN;
		nexp->mDecType = vexp->mDecType;
		nexp->mLeft = vexp;
		ConsumeToken(TK_OPEN_PARENTHESIS);
		if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
		{
			nexp->mRight = ParseRExpression();
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}

		return nexp;
	}
}

void Parser::PrependMemberConstructor(Declaration* pthis, Declaration* cfunc)
{
	if (cfunc->mFlags & DTF_COMPLETED)
		return;

	cfunc->mFlags |= DTF_COMPLETED;

	Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
	pthisexp->mDecType = pthis;
	pthisexp->mDecValue = cfunc->mBase->mParams;

	Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
	thisexp->mToken = TK_MUL;
	thisexp->mDecType = pthis->mBase;
	thisexp->mLeft = pthisexp;

	Declaration* bcdec = pthis->mBase->mBase;
	while (bcdec)
	{
		Declaration* mfunc = cfunc->mScope ? cfunc->mScope->Lookup(bcdec->mBase->mIdent) : nullptr;

		if (mfunc)
		{
			Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE);
			sexp->mLeft = mfunc->mValue;
			sexp->mRight = cfunc->mValue;
			cfunc->mValue = sexp;
		}
		else if (bcdec->mBase->mDefaultConstructor)
		{
			Declaration* mdec = bcdec->mBase->mDefaultConstructor;

			Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
			cexp->mDecValue = mdec;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression * dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = pthisexp;

			Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);

			sexp->mLeft = dexp;
			sexp->mRight = cfunc->mValue;
			cfunc->mValue = sexp;
		}

		bcdec = bcdec->mNext;
	}

	Declaration* dec = pthis->mBase->mParams;
	if (dec)
	{

		dec = dec->Last();
		while (dec)
		{
			if (dec->mType == DT_ELEMENT)
			{
				Declaration* mfunc = cfunc->mScope ? cfunc->mScope->Lookup(dec->mIdent) : nullptr;

				if (mfunc)
				{
					Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE);
					sexp->mLeft = mfunc->mValue;
					sexp->mRight = cfunc->mValue;
					cfunc->mValue = sexp;
				}
				else 
				{
					Declaration* bdec = dec->mBase;
					while (bdec->mType == DT_TYPE_ARRAY)
						bdec = bdec->mBase;

					if (bdec->mFlags & DTF_PURE_VIRTUAL)
						mErrors->Error(dec->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", dec->mIdent);

					if (bdec->mType == DT_TYPE_STRUCT && bdec->mDefaultConstructor || dec->mValue)
					{
						bdec = bdec->ToMutableType();

						Declaration* bpdec = bdec->BuildPointer(mScanner->mLocation);

						Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY);
						qexp->mLeft = thisexp;
						qexp->mDecValue = dec;

						Expression* dexp;

						if (bdec->mDefaultConstructor)
						{
							if (dec->mBase->mType == DT_TYPE_STRUCT)
							{
								qexp->mDecType = bdec;

								if (dec->mValue)
									dexp = BuildVariableInit(qexp, dec->mValue);
								else
								{
									Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
									pexp->mLeft = qexp;
									pexp->mToken = TK_BINARY_AND;
									pexp->mDecType = bpdec;

									Declaration* mdec = bdec->mDefaultConstructor;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									if (mdec)
									{
										cexp->mDecValue = mdec;
										cexp->mDecType = cexp->mDecValue->mBase;
									}
									else
										mErrors->Error(dec->mLocation, EERR_NO_DEFAULT_CONSTRUCTOR, "No default constructor");

									dexp = new Expression(mScanner->mLocation, EX_CALL);
									dexp->mLeft = cexp;
									dexp->mRight = pexp;
								}
							}
							else
							{								
								qexp->mDecType = dec->mBase->mBase;

								Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
								pexp->mLeft = qexp;
								pexp->mToken = TK_BINARY_AND;
								pexp->mDecType = bpdec;

								qexp = pexp;

								if (dec->mValue)
								{
									int offset = 0;
									dexp = BuildVariableArrayInit(qexp, bpdec, dec->mValue->mDecValue, 0, offset);
#if 0
									int offset = 0;
									dexp = nullptr;

									Declaration* pdec = dec->mValue->mDecValue->mParams;
									while (pdec)
									{
										if (pdec->mType == DT_CONST_CONSTRUCTOR)
										{
											if (offset != pdec->mOffset)
												mErrors->Error(pdec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Incomplete class initializer list");

											Declaration* icdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
											icdec->mBase = TheUnsignedIntTypeDeclaration;
											icdec->mInteger = pdec->mOffset / bdec->mSize;

											Expression* icexp = new Expression(mScanner->mLocation, EX_CONSTANT);
											icexp->mDecType = icdec->mBase;
											icexp->mDecValue = icdec;

											Expression* mexp = new Expression(mScanner->mLocation, EX_BINARY);
											mexp->mToken = TK_ADD;
											mexp->mLeft = qexp;
											mexp->mRight = icexp;
											mexp->mDecType = bpdec;
											
											Expression* pv = new Expression(pdec->mValue->mLocation, EX_CONSTRUCT);
											pv->mLeft = new Expression(pdec->mValue->mLeft->mLocation, EX_LIST);
											pv->mLeft->mLeft = new Expression(pdec->mValue->mLeft->mLeft->mLocation, EX_CALL);
											pv->mLeft->mLeft->mLeft = pdec->mValue->mLeft->mLeft->mLeft;
											pv->mLeft->mLeft->mDecType = pdec->mValue->mLeft->mLeft->mDecType;
											pv->mLeft->mLeft->mRight = new Expression(pdec->mValue->mLeft->mLeft->mRight->mLocation, EX_LIST);
											pv->mLeft->mLeft->mRight->mRight = pdec->mValue->mLeft->mLeft->mRight->mRight;
											pv->mLeft->mLeft->mRight->mLeft = mexp;

											if (dexp)
											{
												Expression* nexp = new Expression(mScanner->mLocation, EX_LIST);
												nexp->mLeft = dexp;
												nexp->mRight = pv;
												dexp = nexp;
											}
											else
												dexp = pv;

											offset += bdec->mSize;
										}
										else
											mErrors->Error(pdec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Invalid class initializer");

										pdec = pdec->mNext;
									}
#endif
									if (offset != dec->mSize)
										mErrors->Error(dec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Incomplete class initializer list");
								}
								else
								{
									while (qexp->mDecType->mType == DT_TYPE_ARRAY)
									{
										Expression* iexp = new Expression(pthis->mLocation, EX_PREFIX);
										iexp->mToken = TK_MUL;
										iexp->mLeft = qexp;
										iexp->mDecType = qexp->mDecType->mBase;
										qexp = iexp;
									}

									qexp->mDecType = bpdec;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									cexp->mDecValue = bdec->mVectorConstructor;
									cexp->mDecType = cexp->mDecValue->mBase;

									Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
									ncdec->mBase = TheUnsignedIntTypeDeclaration;
									ncdec->mInteger = dec->mSize / bdec->mSize;

									dexp = new Expression(mScanner->mLocation, EX_CALL);
									dexp->mLeft = cexp;
									dexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
									dexp->mRight->mLeft = qexp;
									dexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY);
									dexp->mRight->mRight->mToken = TK_ADD;
									dexp->mRight->mRight->mLeft = qexp;
									dexp->mRight->mRight->mDecType = qexp->mDecType;
									dexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
									dexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
									dexp->mRight->mRight->mRight->mDecValue = ncdec;
								}
							}
						}
						else
						{
							qexp->mDecType = dec->mBase;

							dexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							dexp->mToken = TK_ASSIGN;
							dexp->mDecType = dec->mBase;
							dexp->mLeft = qexp;
							dexp->mRight = dec->mValue;
						}

						Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);

						sexp->mLeft = dexp;
						sexp->mRight = cfunc->mValue;
						cfunc->mValue = sexp;
					}
				}
			}

			dec = dec->mPrev;
		}
	}

	if (pthis->mBase->mVTable)
	{
		Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE);
		sexp->mLeft = cfunc->mValue;

		Expression* vexp = new Expression(pthis->mLocation, EX_QUALIFY);
		vexp->mLeft = thisexp;
		vexp->mDecValue = new Declaration(pthis->mLocation, DT_ELEMENT);
		vexp->mDecValue->mBase = TheCharTypeDeclaration;
		vexp->mDecValue->mOffset = pthis->mBase->mVTable->mOffset;
		vexp->mDecValue->mSize = 1;
		vexp->mDecType = TheCharTypeDeclaration;

		Expression* nexp = new Expression(cfunc->mLocation, EX_INITIALIZATION);
		nexp->mToken = TK_ASSIGN;
		nexp->mDecType = TheCharTypeDeclaration;
		nexp->mLeft = vexp;
		nexp->mRight = new Expression(cfunc->mLocation, EX_CONSTANT);
		nexp->mRight->mDecType = TheCharTypeDeclaration;
		nexp->mRight->mDecValue = pthis->mBase->mVTable->mDefaultConstructor;

		sexp->mRight = nexp;
		cfunc->mValue = sexp;
	}
}

void Parser::BuildMemberConstructor(Declaration* pthis, Declaration* cfunc)
{
	Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
	pthisexp->mDecType = pthis;
	pthisexp->mDecValue = cfunc->mBase->mParams;

	Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
	thisexp->mToken = TK_MUL;
	thisexp->mDecType = pthis->mBase;
	thisexp->mLeft = pthisexp;

	cfunc->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

	DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_FUNCTION);
	mScope = scope;

	Declaration* pdec = cfunc->mBase->mParams;
	while (pdec)
	{
		if (pdec->mIdent)
			scope->Insert(pdec->mIdent, pdec);
		pdec = pdec->mNext;
	}
	if (cfunc->mBase->mParamPack)
		mScope->Insert(cfunc->mBase->mParamPack->mIdent, cfunc->mBase->mParamPack);

	Declaration* othis = mThisPointer;
	mThisPointer = pthis;

	mScanner->NextToken();
	do {
		if (ExpectToken(TK_IDENT))
		{
			Declaration* dec = pthis->mBase->mScope->Lookup(mScanner->mTokenIdent);

			Declaration* pcdec = pthis->mBase->mBase;
			while (pcdec && pcdec->mBase->mIdent != mScanner->mTokenIdent)
				pcdec = pcdec->mNext;

			if (pcdec)
			{
				Expression* qexp = new Expression(mScanner->mLocation, EX_PREFIX);
				qexp->mToken = TK_MUL;
				qexp->mDecType = pcdec->mBase->ToMutableType();
				qexp->mLeft = pthisexp;

				Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
				dec->mIdent = mScanner->mTokenIdent;

				mScanner->NextToken();

				dec->mValue = BuildMemberInitializer(qexp);

				cfunc->mScope->Insert(dec->mIdent, dec);
			}
			else if (dec && dec->mType == DT_ELEMENT)
			{
				Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY);
				qexp->mLeft = thisexp;
				qexp->mDecValue = dec;
				qexp->mDecType = dec->mBase->ToMutableType();

				Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
				dec->mIdent = mScanner->mTokenIdent;

				mScanner->NextToken();

				dec->mValue = BuildMemberInitializer(qexp);

				cfunc->mScope->Insert(dec->mIdent, dec);
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Base class or member not found", mScanner->mTokenIdent);
		}

	} while (ConsumeTokenIf(TK_COMMA));

	mScope = mScope->mParent;
	mThisPointer = othis;
}

void Parser::AddDefaultConstructors(Declaration* pthis)
{
	bool	simpleDestructor = true, simpleAssignment = true, simpleConstructor = true, simpleCopy = true, simpleMove = true;
	bool	inlineDestructor = true;
	bool	inlineConstructor = true;
	bool	inlineCopy = true;
	bool	inlineMove = true;
	bool	explicitDestructor = false;
	bool	canMoveConstruct = true;

	const Ident* dtorident = pthis->mBase->mIdent->PreMangle("~");;
	const Ident* ctorident = pthis->mBase->mIdent->PreMangle("+");;
	const Ident* ctorqident = pthis->mBase->mScope->Mangle(ctorident);
	const Ident* cvtorident = pthis->mBase->mIdent->PreMangle("*");;
	const Ident* cvtorqident = pthis->mBase->mScope->Mangle(cvtorident);
	const Ident* cvmtorident = pthis->mBase->mIdent->PreMangle("*&");;

	const Ident* asgnident = pthis->mBase->mIdent->PreMangle("=");;
	const Ident* asgnvident = pthis->mBase->mIdent->PreMangle("=*=");;
	const Ident* asgnvmident = pthis->mBase->mIdent->PreMangle("=*&=");;


	// Extract constructor and destructor from scope

	Declaration* cdec = pthis->mBase->mScope->Lookup(ctorident, SLEVEL_SCOPE);
	while (cdec)
	{
		Declaration* ctdec = cdec->mBase;
		Declaration* tparam = ctdec->mParams->mNext;

		if (!tparam)
			pthis->mBase->mDefaultConstructor = cdec;
		else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_REFERENCE && pthis->mBase->IsConstSame(tparam->mBase->mBase))
			pthis->mBase->mCopyConstructor = cdec;
		else if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_RVALUEREF && pthis->mBase->IsConstSame(tparam->mBase->mBase))
			pthis->mBase->mMoveConstructor = cdec;

		cdec = cdec->mNext;
	}

	Declaration* ddec = pthis->mBase->mScope->Lookup(dtorident, SLEVEL_SCOPE);
	if (ddec)
	{
		pthis->mBase->mDestructor = ddec;
		explicitDestructor = true;
	}

	Declaration* adec = pthis->mBase->mScope->Lookup(Ident::Unique("operator="), SLEVEL_SCOPE);
	while (adec)
	{
		Declaration* atdec = adec->mBase;
		Declaration* tparam = atdec->mParams->mNext;

		if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_REFERENCE && pthis->mBase->IsConstSame(tparam->mBase->mBase))
			pthis->mBase->mCopyAssignment = adec;
		if (!tparam->mNext && tparam->mBase->mType == DT_TYPE_RVALUEREF && pthis->mBase->IsSame(tparam->mBase->mBase))
			pthis->mBase->mMoveAssignment = adec;

		adec = adec->mNext;
	}

	Declaration* bcdec = pthis->mBase->mBase;
	while (bcdec)
	{
		if (bcdec->mBase->mDestructor)
		{
			if (!(bcdec->mBase->mDestructor->mBase->mFlags & DTF_REQUEST_INLINE))
				inlineConstructor = false;
			simpleDestructor = false;
		}
		if (bcdec->mBase->mDefaultConstructor)
		{
			simpleConstructor = false;
			if (!(bcdec->mBase->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
				inlineConstructor = false;
		}
		if (bcdec->mBase->mCopyConstructor)
		{
			simpleCopy = false;
			if (!(bcdec->mBase->mCopyConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
				inlineCopy = false;
		}
		if (bcdec->mBase->mMoveConstructor)
		{
			simpleMove = false;
			if (!(bcdec->mBase->mMoveConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
				inlineMove = false;
		}
		else if (bcdec->mBase->mDestructor || bcdec->mBase->mDefaultConstructor || bcdec->mBase->mCopyConstructor)
			canMoveConstruct = false;

		if (bcdec->mBase->mCopyAssignment)
			simpleAssignment = false;
		bcdec = bcdec->mNext;
	}

	if (pthis->mBase->mVTable)
		simpleConstructor = false;

	if (explicitDestructor)
	{
		simpleCopy = false;
		simpleAssignment = false;
		canMoveConstruct = false;
	}

	Declaration* dec = pthis->mBase->mParams;
	while (dec)
	{
		if (dec->mType == DT_ELEMENT)
		{
			Declaration* bdec = dec->mBase;
			int			nitems = 1;

			while (bdec->mType == DT_TYPE_ARRAY)
				bdec = bdec->mBase;

			if (bdec->mFlags & DTF_PURE_VIRTUAL)
				mErrors->Error(dec->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", dec->mIdent);

			if (bdec->mType == DT_TYPE_STRUCT)
			{
				if (bdec->mDestructor)
				{
					simpleDestructor = false;
					if (!(bdec->mDestructor->mBase->mFlags & DTF_REQUEST_INLINE))
						inlineDestructor = false;
				}
				if (bdec->mDefaultConstructor)
				{
					simpleConstructor = false;
					if (!(bdec->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
						inlineConstructor = false;
				}
				if (bdec->mCopyConstructor)
					simpleCopy = false;
				if (bdec->mCopyAssignment || bdec->mMoveAssignment)
					simpleAssignment = false;
				if (bdec->mMoveConstructor)
					simpleMove = false;
				else if (bdec->mDestructor || bdec->mDefaultConstructor || bdec->mCopyConstructor)
					canMoveConstruct = false;
			}
			if (dec->mValue)
				simpleConstructor = false;
		}
		dec = dec->mNext;
	}

	if (!simpleDestructor)
	{
		if (!pthis->mBase->mDestructor)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;
			Declaration* pdec = nullptr;
			ctdec->mBase = TheVoidTypeDeclaration;
			ctdec->mFlags |= DTF_DEFINED;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			if (inlineDestructor)
				cdec->mFlags |= DTF_REQUEST_INLINE;

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mIdent = dtorident;
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			cdec->mFlags |= DTF_DEFINED;

			cdec->mValue = new Expression(mScanner->mLocation, EX_VOID);

			pthis->mBase->mDestructor = AddMemberFunction(pthis->mBase, cdec);

		}
	}

	if (!simpleConstructor)
	{
		if (!pthis->mBase->mDefaultConstructor)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;

			ctdec->mBase = TheVoidTypeDeclaration;
			ctdec->mFlags |= DTF_DEFINED;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;
			cdec->mIdent = ctorident;
			cdec->mQualIdent = ctorqident;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			if (inlineConstructor)
				cdec->mFlags |= DTF_REQUEST_INLINE;

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			cdec->mFlags |= DTF_DEFINED;

			cdec->mValue = new Expression(mScanner->mLocation, EX_VOID);

			pthis->mBase->mDefaultConstructor = AddMemberFunction(pthis->mBase, cdec);
		}
	}

	if (!simpleCopy)
	{
		if (!pthis->mBase->mCopyConstructor)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;
			ctdec->mBase = TheVoidTypeDeclaration;
			ctdec->mFlags |= DTF_DEFINED;

			Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
			adec->mVarIndex = 0;
			adec->mOffset = 0;
			adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE);
			adec->mBase->mSize = 2;
			adec->mBase->mBase = pthis->mBase->ToConstType();
			adec->mBase->mFlags |= DTF_CONST | DTF_DEFINED;
			adec->mSize = adec->mBase->mSize;
			adec->mIdent = adec->mQualIdent = Ident::Unique("_");

			ctdec->mParams = adec;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			if (inlineCopy)
				cdec->mFlags |= DTF_REQUEST_INLINE;

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			pthis->mBase->mCopyConstructor = cdec;

			cdec->mIdent = ctorident;
			cdec->mQualIdent = ctorqident;

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			if (explicitDestructor)
				cdec->mFlags |= DTF_DEPRECATED;

			cdec->mValue = new Expression(mScanner->mLocation, EX_VOID);

			// Now add all the copying

			Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
			pthisexp->mDecType = pthis;
			pthisexp->mDecValue = cdec->mBase->mParams;

			Expression* thisexp = new Expression(pthis->mLocation, EX_PREFIX);
			thisexp->mToken = TK_MUL;
			thisexp->mDecType = pthis->mBase;
			thisexp->mLeft = pthisexp;

			Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE);
			thatexp->mDecType = adec->mBase;
			thatexp->mDecValue = cdec->mBase->mParams->mNext;

			cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

			pthis->mBase->mCopyConstructor = AddMemberFunction(pthis->mBase, cdec);
			if (pthis->mBase->mCopyConstructor == cdec)
			{
				// Copy base class

				Declaration* bcdec = pthis->mBase->mBase;
				while (bcdec)
				{
					if (bcdec->mBase->mCopyConstructor)
					{
						Declaration* mdec = bcdec->mBase->mCopyConstructor;

						Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
						cexp->mDecValue = mdec;
						cexp->mDecType = cexp->mDecValue->mBase;

						Expression* dexp = new Expression(pthis->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
						dexp->mRight->mLeft = pthisexp;
						dexp->mRight->mRight = thatexp;

						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = bcdec->mBase->mIdent;
						mcdec->mValue = dexp;

						cdec->mScope->Insert(bcdec->mBase->mIdent, mcdec);
					}
					else
					{
						Expression* cexp = new Expression(pthis->mLocation, EX_TYPECAST);
						cexp->mLeft = pthisexp;
						cexp->mDecType = bcdec->mBase->BuildPointer(pthis->mLocation);

						Expression* cexp2 = new Expression(pthis->mLocation, EX_PREFIX);
						cexp2->mToken = TK_MUL;
						cexp2->mDecType = bcdec->mBase;
						cexp2->mLeft = cexp;

						Expression* dexp = new Expression(pthis->mLocation, EX_INITIALIZATION);
						dexp->mToken = TK_ASSIGN;
						dexp->mLeft = cexp2;
						dexp->mRight = thatexp;
						
						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = bcdec->mBase->mIdent;
						mcdec->mValue = dexp;

						cdec->mScope->Insert(bcdec->mBase->mIdent, mcdec);
					}

					bcdec = bcdec->mNext;
				}

				Declaration* dec = pthis->mBase->mParams;
				while (dec)
				{
					if (dec->mType == DT_ELEMENT)
					{
						Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY);
						lexp->mLeft = thisexp;
						lexp->mDecValue = dec;
						lexp->mDecType = dec->mBase;

						Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY);
						rexp->mLeft = thatexp;
						rexp->mDecValue = dec;
						rexp->mDecType = dec->mBase;

						Expression* mexp;

						Declaration* bdec = dec->mBase;
						while (bdec->mType == DT_TYPE_ARRAY)
							bdec = bdec->mBase;

						bdec = bdec->ToMutableType();

						if (bdec->mType == DT_TYPE_STRUCT && bdec->mCopyConstructor)
						{
							Declaration* bpdec = bdec->BuildPointer(bdec->mLocation);

							if (dec->mBase->mType == DT_TYPE_STRUCT)
							{
								Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
								pexp->mLeft = lexp;
								pexp->mToken = TK_BINARY_AND;
								pexp->mDecType = bpdec;

								Declaration* mdec = dec->mBase->mCopyConstructor;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = mdec;
								cexp->mDecType = cexp->mDecValue->mBase;

								mexp = new Expression(mScanner->mLocation, EX_CALL);
								mexp->mLeft = cexp;
								mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mLeft = pexp;
								mexp->mRight->mRight = rexp;
							}
							else
							{
								Expression* lpexp = new Expression(pthis->mLocation, EX_PREFIX);
								lpexp->mLeft = lexp;
								lpexp->mToken = TK_BINARY_AND;
								lpexp->mDecType = bpdec;

								Expression* rpexp = new Expression(pthis->mLocation, EX_PREFIX);
								rpexp->mLeft = rexp;
								rpexp->mToken = TK_BINARY_AND;
								rpexp->mDecType = bpdec;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = bdec->mVectorCopyConstructor;
								cexp->mDecType = cexp->mDecValue->mBase;

								Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								ncdec->mBase = TheUnsignedIntTypeDeclaration;
								ncdec->mInteger = dec->mSize / bdec->mSize;

								mexp = new Expression(mScanner->mLocation, EX_CALL);
								mexp->mLeft = cexp;
								mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mLeft = lpexp;
								mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mRight->mLeft = rpexp;
								mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								mexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
								mexp->mRight->mRight->mRight->mDecValue = ncdec;

							}
						}
						else
						{
							mexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							mexp->mToken = TK_ASSIGN;
							mexp->mLeft = lexp;
							mexp->mRight = rexp;
							mexp->mDecType = lexp->mDecType;
						}

						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = dec->mIdent;
						mcdec->mValue = mexp;

						cdec->mScope->Insert(dec->mIdent, mcdec);
					}

					dec = dec->mNext;
				}
			}

			cdec->mFlags |= DTF_DEFINED;
		}

#if 1
		if (!pthis->mBase->mMoveConstructor && canMoveConstruct)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;
			ctdec->mBase = TheVoidTypeDeclaration;
			ctdec->mFlags |= DTF_DEFINED;

			Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
			adec->mVarIndex = 0;
			adec->mOffset = 0;
			adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_RVALUEREF);
			adec->mBase->mSize = 2;
			adec->mBase->mBase = pthis->mBase;
			adec->mBase->mFlags |= DTF_DEFINED;
			adec->mSize = adec->mBase->mSize;
			adec->mIdent = adec->mQualIdent = Ident::Unique("_");

			ctdec->mParams = adec;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			if (inlineCopy)
				cdec->mFlags |= DTF_REQUEST_INLINE;

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			pthis->mBase->mMoveConstructor = cdec;

			cdec->mIdent = ctorident;
			cdec->mQualIdent = ctorqident;

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			cdec->mValue = new Expression(mScanner->mLocation, EX_VOID);

			// Now add all the moving

			Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
			pthisexp->mDecType = pthis;
			pthisexp->mDecValue = cdec->mBase->mParams;

			Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
			thisexp->mToken = TK_MUL;
			thisexp->mDecType = pthis->mBase;
			thisexp->mLeft = pthisexp;

			Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE);
			thatexp->mDecType = adec->mBase;
			thatexp->mDecValue = cdec->mBase->mParams->mNext;

			cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

			pthis->mBase->mMoveConstructor = AddMemberFunction(pthis->mBase, cdec);
			if (pthis->mBase->mMoveConstructor == cdec)
			{
				// Move base class

				Declaration* bcdec = pthis->mBase->mBase;
				while (bcdec)
				{
					if (bcdec->mBase->mMoveConstructor)
					{
						Declaration* mdec = bcdec->mBase->mMoveConstructor;

						Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
						cexp->mDecValue = mdec;
						cexp->mDecType = cexp->mDecValue->mBase;

						Expression* dexp = new Expression(pthis->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
						dexp->mRight->mLeft = pthisexp;
						dexp->mRight->mRight = thatexp;

						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = bcdec->mBase->mIdent;
						mcdec->mValue = dexp;

						cdec->mScope->Insert(bcdec->mBase->mIdent, mcdec);
					}
					else
					{
						Expression* cexp = new Expression(pthis->mLocation, EX_TYPECAST);
						cexp->mLeft = pthisexp;
						cexp->mDecType = bcdec->mBase->BuildPointer(pthis->mLocation);

						Expression* cexp2 = new Expression(pthis->mLocation, EX_PREFIX);
						cexp2->mToken = TK_MUL;
						cexp2->mDecType = bcdec->mBase;
						cexp2->mLeft = cexp;

						Expression* dexp = new Expression(pthis->mLocation, EX_INITIALIZATION);
						dexp->mToken = TK_ASSIGN;
						dexp->mLeft = cexp2;
						dexp->mRight = thatexp;

						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = bcdec->mBase->mIdent;
						mcdec->mValue = dexp;

						cdec->mScope->Insert(bcdec->mBase->mIdent, mcdec);
					}

					bcdec = bcdec->mNext;
				}

				Declaration* dec = pthis->mBase->mParams;
				while (dec)
				{
					if (dec->mType == DT_ELEMENT)
					{
						Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY);
						lexp->mLeft = thisexp;
						lexp->mDecValue = dec;
						lexp->mDecType = dec->mBase;

						Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY);
						rexp->mLeft = thatexp;
						rexp->mDecValue = dec;
						rexp->mDecType = dec->mBase;

						Expression* mexp;

						Declaration* bdec = dec->mBase;
						while (bdec->mType == DT_TYPE_ARRAY)
							bdec = bdec->mBase;

						bdec = bdec->ToMutableType();

						if (bdec->mType == DT_TYPE_STRUCT && bdec->mMoveConstructor)
						{
							Declaration* bpdec = bdec->BuildPointer(bdec->mLocation);

							if (dec->mBase->mType == DT_TYPE_STRUCT)
							{
								Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
								pexp->mLeft = lexp;
								pexp->mToken = TK_BINARY_AND;
								pexp->mDecType = bpdec;

								Declaration* mdec = dec->mBase->mMoveConstructor;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = mdec;
								cexp->mDecType = cexp->mDecValue->mBase;

								mexp = new Expression(mScanner->mLocation, EX_CALL);
								mexp->mLeft = cexp;
								mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mLeft = pexp;
								mexp->mRight->mRight = rexp;
							}
							else
							{
								Expression* lpexp = new Expression(pthis->mLocation, EX_PREFIX);
								lpexp->mLeft = lexp;
								lpexp->mToken = TK_BINARY_AND;
								lpexp->mDecType = bpdec;

								Expression* rpexp = new Expression(pthis->mLocation, EX_PREFIX);
								rpexp->mLeft = rexp;
								rpexp->mToken = TK_BINARY_AND;
								rpexp->mDecType = bpdec;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = bdec->mVectorMoveConstructor;
								cexp->mDecType = cexp->mDecValue->mBase;

								Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								ncdec->mBase = TheUnsignedIntTypeDeclaration;
								ncdec->mInteger = dec->mSize / bdec->mSize;

								mexp = new Expression(mScanner->mLocation, EX_CALL);
								mexp->mLeft = cexp;
								mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mLeft = lpexp;
								mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST);
								mexp->mRight->mRight->mLeft = rpexp;
								mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								mexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
								mexp->mRight->mRight->mRight->mDecValue = ncdec;

							}
						}
						else
						{
							mexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							mexp->mToken = TK_ASSIGN;
							mexp->mLeft = lexp;
							mexp->mRight = rexp;
							mexp->mDecType = lexp->mDecType;
						}

						Declaration* mcdec = new Declaration(mScanner->mLocation, DT_CONST_CONSTRUCTOR);
						mcdec->mIdent = mScanner->mTokenIdent;
						mcdec->mValue = mexp;

						cdec->mScope->Insert(dec->mIdent, mcdec);
					}

					dec = dec->mNext;
				}
			}

			cdec->mFlags |= DTF_DEFINED;
		}
#endif
	}

	if (!simpleAssignment)
	{
		// Copy assignment operator
		if (!pthis->mBase->mCopyAssignment)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;
			ctdec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE);
			ctdec->mBase->mSize = 2;
			ctdec->mBase->mBase = pthis->mBase;
			ctdec->mBase->mFlags |= DTF_DEFINED;
			ctdec->mFlags |= DTF_DEFINED;

			Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
			adec->mVarIndex = 0;
			adec->mOffset = 0;
			adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE);
			adec->mBase->mSize = 2;
			adec->mBase->mBase = pthis->mBase->ToConstType();
			adec->mBase->mFlags |= DTF_CONST | DTF_DEFINED;
			adec->mSize = adec->mBase->mSize;
			adec->mIdent = adec->mQualIdent = Ident::Unique("_");

			ctdec->mParams = adec;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mIdent = Ident::Unique("operator=");
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			if (explicitDestructor)
				cdec->mFlags |= DTF_DEPRECATED;

			Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
			pthisexp->mDecType = pthis;
			pthisexp->mDecValue = cdec->mBase->mParams;

			Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
			thisexp->mToken = TK_MUL;
			thisexp->mDecType = pthis->mBase->ToMutableType();
			thisexp->mLeft = pthisexp;

			cdec->mValue = new Expression(mScanner->mLocation, EX_RETURN);
			cdec->mValue->mLeft = thisexp;
			cdec->mValue->mDecType = cdec->mBase;

			// Now add all the copying

			Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE);
			thatexp->mDecType = adec->mBase;
			thatexp->mDecValue = cdec->mBase->mParams->mNext;

			cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

			pthis->mBase->mCopyAssignment = AddMemberFunction(pthis->mBase, cdec);
			if (pthis->mBase->mCopyAssignment == cdec)
			{
				Declaration* dec = pthis->mBase->mParams;
				if (dec)
				{
					dec = dec->Last();
					while (dec)
					{
						if (dec->mType == DT_ELEMENT)
						{
							Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY);
							lexp->mLeft = thisexp;
							lexp->mDecValue = dec;
							lexp->mDecType = dec->mBase;

							Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY);
							rexp->mLeft = thatexp;
							rexp->mDecValue = dec;
							rexp->mDecType = dec->mBase;

							Expression* mexp;

							Declaration* bdec = dec->mBase;
							while (bdec->mType == DT_TYPE_ARRAY)
								bdec = bdec->mBase;

							if (bdec->mType == DT_TYPE_STRUCT && bdec->mCopyAssignment)
							{
								Declaration* bpdec = bdec->BuildPointer(bdec->mLocation);

								if (dec->mBase->mType == DT_TYPE_STRUCT)
								{
									Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
									pexp->mLeft = lexp;
									pexp->mToken = TK_BINARY_AND;
									pexp->mDecType = bpdec;

									Declaration* mdec = bdec->mCopyAssignment;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									cexp->mDecValue = mdec;
									cexp->mDecType = cexp->mDecValue->mBase;

									mexp = new Expression(mScanner->mLocation, EX_CALL);
									mexp->mLeft = cexp;
									mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mLeft = pexp;
									mexp->mRight->mRight = rexp;
								}
								else
								{
									Expression* lpexp = new Expression(pthis->mLocation, EX_PREFIX);
									lpexp->mLeft = lexp;
									lpexp->mToken = TK_BINARY_AND;
									lpexp->mDecType = bpdec;

									Expression* rpexp = new Expression(pthis->mLocation, EX_PREFIX);
									rpexp->mLeft = rexp;
									rpexp->mToken = TK_BINARY_AND;
									rpexp->mDecType = bpdec;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									cexp->mDecValue = bdec->mVectorCopyAssignment;
									cexp->mDecType = cexp->mDecValue->mBase;

									Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
									ncdec->mBase = TheUnsignedIntTypeDeclaration;
									ncdec->mInteger = dec->mSize / bdec->mSize;

									mexp = new Expression(mScanner->mLocation, EX_CALL);
									mexp->mLeft = cexp;
									mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mLeft = lpexp;
									mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mRight->mLeft = rpexp;
									mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
									mexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
									mexp->mRight->mRight->mRight->mDecValue = ncdec;
								}
							}
							else
							{
								mexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
								mexp->mToken = TK_ASSIGN;
								mexp->mLeft = lexp;
								mexp->mRight = rexp;
								mexp->mDecType = lexp->mDecType;
							}

							Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
							sexp->mLeft = mexp;
							sexp->mRight = cdec->mValue;
							cdec->mValue = sexp;
						}

						dec = dec->mPrev;
					}
				}
			}

			cdec->mFlags |= DTF_DEFINED;
		}

		// Move assignment operator
		if (!pthis->mBase->mMoveAssignment && canMoveConstruct)
		{
			Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
			ctdec->mSize = 0;
			ctdec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_REFERENCE);
			ctdec->mBase->mSize = 2;
			ctdec->mBase->mBase = pthis->mBase;
			ctdec->mBase->mFlags |= DTF_DEFINED;
			ctdec->mFlags |= DTF_DEFINED;

			Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
			adec->mVarIndex = 0;
			adec->mOffset = 0;
			adec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_RVALUEREF);
			adec->mBase->mSize = 2;
			adec->mBase->mBase = pthis->mBase;
			adec->mBase->mFlags |= DTF_DEFINED;
			adec->mSize = adec->mBase->mSize;
			adec->mIdent = adec->mQualIdent = Ident::Unique("_");

			ctdec->mParams = adec;

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

			cdec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mIdent = Ident::Unique("operator=");
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			cdec->mCompilerOptions = mCompilerOptions;
			cdec->mBase->mCompilerOptions = mCompilerOptions;

			cdec->mVarIndex = -1;

			if (explicitDestructor)
				cdec->mFlags |= DTF_DEPRECATED;

			Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
			pthisexp->mDecType = pthis;
			pthisexp->mDecValue = cdec->mBase->mParams;

			Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
			thisexp->mToken = TK_MUL;
			thisexp->mDecType = pthis->mBase->ToMutableType();
			thisexp->mLeft = pthisexp;

			cdec->mValue = new Expression(mScanner->mLocation, EX_RETURN);
			cdec->mValue->mLeft = thisexp;
			cdec->mValue->mDecType = cdec->mBase;

			// Now add all the copying

			Expression* thatexp = new Expression(pthis->mLocation, EX_VARIABLE);
			thatexp->mDecType = adec->mBase;
			thatexp->mDecValue = cdec->mBase->mParams->mNext;

			cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);

			pthis->mBase->mMoveAssignment = AddMemberFunction(pthis->mBase, cdec);
			if (pthis->mBase->mMoveAssignment == cdec)
			{
				Declaration* dec = pthis->mBase->mParams;
				if (dec)
				{
					dec = dec->Last();
					while (dec)
					{
						if (dec->mType == DT_ELEMENT)
						{
							Expression* lexp = new Expression(pthis->mLocation, EX_QUALIFY);
							lexp->mLeft = thisexp;
							lexp->mDecValue = dec;
							lexp->mDecType = dec->mBase;

							Expression* rexp = new Expression(pthis->mLocation, EX_QUALIFY);
							rexp->mLeft = thatexp;
							rexp->mDecValue = dec;
							rexp->mDecType = dec->mBase;

							Expression* mexp;

							Declaration* bdec = dec->mBase;
							while (bdec->mType == DT_TYPE_ARRAY)
								bdec = bdec->mBase;

							if (bdec->mType == DT_TYPE_STRUCT && bdec->mMoveAssignment)
							{
								Declaration* bpdec = bdec->BuildPointer(bdec->mLocation);

								if (dec->mBase->mType == DT_TYPE_STRUCT)
								{
									Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
									pexp->mLeft = lexp;
									pexp->mToken = TK_BINARY_AND;
									pexp->mDecType = bpdec;

									Declaration* mdec = bdec->mMoveAssignment;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									cexp->mDecValue = mdec;
									cexp->mDecType = cexp->mDecValue->mBase;

									mexp = new Expression(mScanner->mLocation, EX_CALL);
									mexp->mLeft = cexp;
									mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mLeft = pexp;
									mexp->mRight->mRight = rexp;
								}
								else
								{
									Expression* lpexp = new Expression(pthis->mLocation, EX_PREFIX);
									lpexp->mLeft = lexp;
									lpexp->mToken = TK_BINARY_AND;
									lpexp->mDecType = bpdec;

									Expression* rpexp = new Expression(pthis->mLocation, EX_PREFIX);
									rpexp->mLeft = rexp;
									rpexp->mToken = TK_BINARY_AND;
									rpexp->mDecType = bpdec;

									Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
									cexp->mDecValue = bdec->mVectorMoveAssignment;
									cexp->mDecType = cexp->mDecValue->mBase;

									Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
									ncdec->mBase = TheUnsignedIntTypeDeclaration;
									ncdec->mInteger = dec->mSize / bdec->mSize;

									mexp = new Expression(mScanner->mLocation, EX_CALL);
									mexp->mLeft = cexp;
									mexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mLeft = lpexp;
									mexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST);
									mexp->mRight->mRight->mLeft = rpexp;
									mexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
									mexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
									mexp->mRight->mRight->mRight->mDecValue = ncdec;
								}
							}
							else
							{
								mexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
								mexp->mToken = TK_ASSIGN;
								mexp->mLeft = lexp;
								mexp->mRight = rexp;
								mexp->mDecType = lexp->mDecType;
							}

							Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
							sexp->mLeft = mexp;
							sexp->mRight = cdec->mValue;
							cdec->mValue = sexp;
						}

						dec = dec->mPrev;
					}
				}
			}

			cdec->mFlags |= DTF_DEFINED;
		}
	}

	if (pthis->mBase->mDefaultConstructor && !pthis->mBase->mVectorConstructor)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 0;
		adec->mOffset = 0;
		adec->mBase = pthis;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("end");

		ctdec->mParams = adec;

		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = cvtorident;
		cdec->mQualIdent = cvtorqident;

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorConstructor = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorConstructor == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = pthis;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mDefaultConstructor;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = iexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
			wexp->mLeft->mToken = TK_NOT_EQUAL;
			wexp->mLeft->mLeft = pexp;
			wexp->mLeft->mRight = aexp;
			wexp->mLeft->mDecType = TheBoolTypeDeclaration;
			wexp->mRight = cexp;

			cdec->mValue = wexp;
		}
	}

	if (pthis->mBase->mDestructor && !pthis->mBase->mVectorDestructor)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 0;
		adec->mOffset = 0;
		adec->mBase = pthis;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("end");

		ctdec->mParams = adec;

		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = dtorident;
		cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorDestructor = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorDestructor == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = pthis;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mDestructor;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = iexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
			wexp->mLeft->mToken = TK_NOT_EQUAL;
			wexp->mLeft->mLeft = pexp;
			wexp->mLeft->mRight = aexp;
			wexp->mLeft->mDecType = TheBoolTypeDeclaration;

			wexp->mRight = cexp;

			cdec->mValue = wexp;
		}
	}

	if (pthis->mBase->mCopyConstructor && !pthis->mBase->mVectorCopyConstructor)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		sdec->mVarIndex = 0;
		sdec->mOffset = 0;
		sdec->mBase = pthis->Clone();
		sdec->mBase->mFlags &= ~DTF_CONST;
		sdec->mSize = sdec->mBase->mSize;
		sdec->mIdent = sdec->mQualIdent = Ident::Unique("_");

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 2;
		adec->mOffset = 0;
		adec->mBase = TheUnsignedIntTypeDeclaration;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("n");

		sdec->mNext = adec;
		ctdec->mParams = sdec;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;
		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = cvtorident;
		cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorCopyConstructor = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorCopyConstructor == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			psexp->mDecType = vthis;
			psexp->mDecValue = sdec;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = TheUnsignedIntTypeDeclaration;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			isexp->mToken = TK_INC;
			isexp->mLeft = psexp;
			isexp->mDecType = psexp->mDecType;

			Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX);
			disexp->mToken = TK_MUL;
			disexp->mLeft = isexp;
			disexp->mDecType = vthis->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			dexp->mToken = TK_DEC;
			dexp->mLeft = aexp;
			dexp->mDecType = aexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mCopyConstructor;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
			cexp->mRight->mLeft = iexp;
			cexp->mRight->mRight = disexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = aexp;
			wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
			wexp->mRight->mLeft = cexp;
			wexp->mRight->mRight = dexp;

			cdec->mValue = wexp;
		}
	}

	if (pthis->mBase->mMoveConstructor && !pthis->mBase->mVectorMoveConstructor)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		sdec->mVarIndex = 0;
		sdec->mOffset = 0;
		sdec->mBase = pthis->Clone();
		sdec->mBase->mFlags &= ~DTF_CONST;
		sdec->mSize = sdec->mBase->mSize;
		sdec->mIdent = sdec->mQualIdent = Ident::Unique("_");

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 2;
		adec->mOffset = 0;
		adec->mBase = TheUnsignedIntTypeDeclaration;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("n");

		sdec->mNext = adec;
		ctdec->mParams = sdec;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;
		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = cvmtorident;
		cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorMoveConstructor = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorMoveConstructor == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			psexp->mDecType = vthis;
			psexp->mDecValue = sdec;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = TheUnsignedIntTypeDeclaration;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			isexp->mToken = TK_INC;
			isexp->mLeft = psexp;
			isexp->mDecType = psexp->mDecType;

			Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX);
			disexp->mToken = TK_MUL;
			disexp->mLeft = isexp;
			disexp->mDecType = vthis->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			dexp->mToken = TK_DEC;
			dexp->mLeft = aexp;
			dexp->mDecType = aexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mMoveConstructor;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
			cexp->mRight->mLeft = iexp;
			cexp->mRight->mRight = disexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = aexp;
			wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
			wexp->mRight->mLeft = cexp;
			wexp->mRight->mRight = dexp;

			cdec->mValue = wexp;
		}
	}

	if (pthis->mBase->mCopyAssignment && !pthis->mBase->mVectorCopyAssignment)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		sdec->mVarIndex = 0;
		sdec->mOffset = 0;
		sdec->mBase = pthis->Clone();
		sdec->mBase->mFlags &= ~DTF_CONST;
		sdec->mSize = sdec->mBase->mSize;
		sdec->mIdent = sdec->mQualIdent = Ident::Unique("_");

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 2;
		adec->mOffset = 0;
		adec->mBase = TheUnsignedIntTypeDeclaration;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("n");

		sdec->mNext = adec;
		ctdec->mParams = sdec;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;
		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = asgnvident;
		cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorCopyAssignment = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorCopyAssignment == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			psexp->mDecType = vthis;
			psexp->mDecValue = sdec;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = TheUnsignedIntTypeDeclaration;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			isexp->mToken = TK_INC;
			isexp->mLeft = psexp;
			isexp->mDecType = psexp->mDecType;

			Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX);
			disexp->mToken = TK_MUL;
			disexp->mLeft = isexp;
			disexp->mDecType = vthis->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			dexp->mToken = TK_DEC;
			dexp->mLeft = aexp;
			dexp->mDecValue = aexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mCopyAssignment;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
			cexp->mRight->mLeft = iexp;
			cexp->mRight->mRight = disexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = aexp;
			wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
			wexp->mRight->mLeft = cexp;
			wexp->mRight->mRight = dexp;

			cdec->mValue = wexp;
		}
	}

	if (pthis->mBase->mMoveAssignment && !pthis->mBase->mVectorMoveAssignment)
	{
		Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
		ctdec->mSize = 0;
		Declaration* pdec = nullptr;
		ctdec->mBase = TheVoidTypeDeclaration;
		ctdec->mFlags |= DTF_DEFINED;

		Declaration* sdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		sdec->mVarIndex = 0;
		sdec->mOffset = 0;
		sdec->mBase = pthis->Clone();
		sdec->mBase->mFlags &= ~DTF_CONST;
		sdec->mSize = sdec->mBase->mSize;
		sdec->mIdent = sdec->mQualIdent = Ident::Unique("_");

		Declaration* adec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
		adec->mVarIndex = 2;
		adec->mOffset = 0;
		adec->mBase = TheUnsignedIntTypeDeclaration;
		adec->mSize = adec->mBase->mSize;
		adec->mIdent = adec->mQualIdent = Ident::Unique("n");

		sdec->mNext = adec;
		ctdec->mParams = sdec;

		Declaration* vthis = pthis->Clone();
		vthis->mFlags &= ~DTF_CONST;
		PrependThisArgument(ctdec, vthis);

		Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
		cdec->mBase = ctdec;

		cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

		cdec->mSection = mCodeSection;

		if (mCompilerOptions & COPT_NATIVE)
			cdec->mFlags |= DTF_NATIVE;

		cdec->mIdent = asgnvmident;
		cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

		cdec->mCompilerOptions = mCompilerOptions;
		cdec->mBase->mCompilerOptions = mCompilerOptions;

		cdec->mVarIndex = -1;

		cdec->mFlags |= DTF_DEFINED;

		pthis->mBase->mVectorMoveAssignment = AddMemberFunction(pthis->mBase, cdec);
		if (pthis->mBase->mVectorMoveAssignment == cdec)
		{
			Expression* pexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			pexp->mDecType = vthis;
			pexp->mDecValue = ctdec->mParams;

			Expression* psexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			psexp->mDecType = vthis;
			psexp->mDecValue = sdec;

			Expression* aexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			aexp->mDecType = TheUnsignedIntTypeDeclaration;
			aexp->mDecValue = adec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			iexp->mToken = TK_INC;
			iexp->mLeft = pexp;
			iexp->mDecType = pexp->mDecType;

			Expression* isexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			isexp->mToken = TK_INC;
			isexp->mLeft = psexp;
			isexp->mDecType = psexp->mDecType;

			Expression* disexp = new Expression(mScanner->mLocation, EX_PREFIX);
			disexp->mToken = TK_MUL;
			disexp->mLeft = isexp;
			disexp->mDecType = vthis->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			dexp->mToken = TK_DEC;
			dexp->mLeft = aexp;
			dexp->mDecValue = aexp->mDecType;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			fexp->mDecValue = pthis->mBase->mMoveAssignment;
			fexp->mDecType = fexp->mDecValue->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CALL);
			cexp->mLeft = fexp;
			cexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
			cexp->mRight->mLeft = iexp;
			cexp->mRight->mRight = disexp;

			Expression* wexp = new Expression(mScanner->mLocation, EX_WHILE);
			wexp->mLeft = aexp;
			wexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
			wexp->mRight->mLeft = cexp;
			wexp->mRight->mRight = dexp;

			cdec->mValue = wexp;
		}
	}
}

void Parser::AppendMemberDestructor(Declaration* pthis)
{
	if (pthis->mBase->mDestructor)
	{
		if (pthis->mBase->mDestructor->mFlags & DTF_DEFINED)
		{
			if (pthis->mBase->mDestructor->mFlags & DTF_COMPLETED)
				return;
			pthis->mBase->mDestructor->mFlags |= DTF_COMPLETED;

			Expression* pthisexp = new Expression(pthis->mLocation, EX_VARIABLE);
			pthisexp->mDecType = pthis;
			pthisexp->mDecValue = pthis->mBase->mDestructor->mBase->mParams;

			Expression* thisexp = new Expression(mScanner->mLocation, EX_PREFIX);
			thisexp->mToken = TK_MUL;
			thisexp->mDecType = pthis->mBase;
			thisexp->mLeft = pthisexp;

			Declaration * dec = pthis->mBase->mParams;
			if (dec)
			{
				dec = dec->Last();
				while (dec)
				{
					if (dec->mType == DT_ELEMENT)
					{
						Declaration* bdec = dec->mBase;
						while (bdec->mType == DT_TYPE_ARRAY)
							bdec = bdec->mBase;

						if (bdec->mType == DT_TYPE_STRUCT && bdec->mDestructor)
						{
							bdec = bdec->ToMutableType();

							Declaration* bpdec = bdec->BuildPointer(pthis->mLocation);

							Expression* qexp = new Expression(pthis->mLocation, EX_QUALIFY);
							qexp->mLeft = thisexp;
							qexp->mDecValue = dec;

							Expression* dexp;

							if (dec->mBase->mType == DT_TYPE_STRUCT)
							{
								qexp->mDecType = bdec;

								Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
								pexp->mLeft = qexp;
								pexp->mToken = TK_BINARY_AND;
								pexp->mDecType = bpdec;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = bdec->mDestructor;
								cexp->mDecType = cexp->mDecValue->mBase;

								dexp = new Expression(mScanner->mLocation, EX_CALL);
								dexp->mLeft = cexp;
								dexp->mRight = pexp;
							}
							else
							{
								qexp->mDecType = dec->mBase->mBase;

								Expression* pexp = new Expression(pthis->mLocation, EX_PREFIX);
								pexp->mLeft = qexp;
								pexp->mToken = TK_BINARY_AND;
								pexp->mDecType = bpdec;

								qexp = pexp;

								while (qexp->mDecType->mType == DT_TYPE_ARRAY)
								{
									Expression* iexp = new Expression(pthis->mLocation, EX_PREFIX);
									iexp->mToken = TK_MUL;
									iexp->mLeft = qexp;
									iexp->mDecType = qexp->mDecType->mBase;
									qexp = iexp;
								}

								qexp->mDecType = new Declaration(pthis->mLocation, DT_TYPE_POINTER);
								qexp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
								qexp->mDecType->mBase = bdec;
								qexp->mDecType->mSize = 2;

								Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
								cexp->mDecValue = bdec->mVectorDestructor;
								cexp->mDecType = cexp->mDecValue->mBase;

								Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								ncdec->mBase = TheUnsignedIntTypeDeclaration;
								ncdec->mInteger = dec->mSize / bdec->mSize;

								dexp = new Expression(mScanner->mLocation, EX_CALL);
								dexp->mLeft = cexp;
								dexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								dexp->mRight->mLeft = qexp;
								dexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY);
								dexp->mRight->mRight->mToken = TK_ADD;
								dexp->mRight->mRight->mLeft = qexp;
								dexp->mRight->mRight->mDecType = qexp->mDecType;
								dexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								dexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
								dexp->mRight->mRight->mRight->mDecValue = ncdec;
							}

							Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);

							sexp->mLeft = pthis->mBase->mDestructor->mValue;
							sexp->mRight = dexp;

							pthis->mBase->mDestructor->mValue = sexp;
						}
					}

					dec = dec->mPrev;
				}
			}

			Declaration* bcdec = pthis->mBase->mBase;
			while (bcdec)
			{
				if (bcdec->mBase->mDestructor)
				{
					Declaration* mdec = bcdec->mBase->mDestructor;

					Expression* cexp = new Expression(pthis->mLocation, EX_CONSTANT);
					cexp->mDecValue = mdec;
					cexp->mDecType = cexp->mDecValue->mBase;

					Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
					dexp->mLeft = cexp;
					dexp->mRight = pthisexp;

					Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);

					sexp->mLeft = pthis->mBase->mDestructor->mValue;
					sexp->mRight = dexp;
					pthis->mBase->mDestructor->mValue = sexp;
				}

				bcdec = bcdec->mNext;
			}
		}
	}
}

void Parser::PrependThisArgument(Declaration* fdec, Declaration* pthis)
{
	Declaration* adec = new Declaration(fdec->mLocation, DT_ARGUMENT);

	if (fdec->mBase && fdec->mBase->mType == DT_TYPE_STRUCT)
		adec->mVarIndex = 2;
	else
		adec->mVarIndex = 0;

	adec->mOffset = 0;
	adec->mBase = pthis;
	adec->mSize = adec->mBase->mSize;
	adec->mNext = fdec->mParams;
	adec->mIdent = adec->mQualIdent = Ident::Unique("this");

	Declaration* p = fdec->mParams;
	while (p)
	{
		p->mVarIndex += 2;
		p = p->mNext;
	}

	fdec->mParams = adec;
	fdec->mClass = pthis;
	fdec->mFlags |= DTF_FUNC_THIS;
}

static Expression* ConcatExpression(Expression* e1, Expression* e2)
{
	if (e1)
	{
		if (e2)
		{
			Expression* seq = new Expression(e1->mLocation, EX_SEQUENCE);
			seq->mLeft = e1;
			seq->mRight = e2;
			return seq;
		}
		return e1;
	}
	else
		return e2;
}

Declaration* Parser::AllocTempVar(Declaration* type)
{
	Declaration* ptemp = nullptr, * vtemp = mTempVars;
	while (vtemp && !vtemp->mBase->IsSame(type))
	{
		ptemp = vtemp;
		vtemp = vtemp->mNext;
	}

	if (vtemp)
	{
		if (ptemp)
			ptemp->mNext = vtemp->mNext;
		else
			mTempVars = vtemp->mNext;
		vtemp->mNext = nullptr;
		vtemp->mValue = nullptr;
	}
	else
	{
		vtemp = new Declaration(mScanner->mLocation, DT_VARIABLE);
		vtemp->mBase = type;
		vtemp->mSize = type->mSize;
		vtemp->mVarIndex = mLocalIndex++;
		vtemp->mFlags |= DTF_DEFINED;
	}

	return vtemp;
}

void Parser::FreeTempVar(Declaration* var)
{
	var->mNext = mTempVars;
	mTempVars = var;
}

void Parser::FreeTempVarExp(Expression* exp)
{
	if (exp->mType == EX_SEQUENCE)
	{
		FreeTempVarExp(exp->mLeft);
		FreeTempVarExp(exp->mRight);
	}
	else if (exp->mType == EX_CALL && exp->mLeft->mType == EX_CONSTANT && 
		exp->mRight->mType == EX_PREFIX && exp->mRight->mToken == TK_BINARY_AND && exp->mRight->mLeft->mType == EX_VARIABLE)
	{
		if (exp->mLeft->mDecValue->mIdent->mString[0] == '~' && exp->mRight->mLeft->mDecValue->mIdent == nullptr)
			FreeTempVar(exp->mRight->mLeft->mDecValue);
	}
}

Expression* Parser::CleanupExpression(Expression* exp)
{
	if (exp)
	{
		Expression* xexp = AddFunctionCallRefReturned(exp);
		if (xexp)
		{
			Expression* cexp = new Expression(exp->mLocation, EX_CLEANUP);
			cexp->mLeft = exp;
			cexp->mRight = xexp;
			cexp->mDecType = exp->mDecType;

			FreeTempVarExp(xexp);
			return cexp;
		}
	}
	return exp;
}

Expression* Parser::AddFunctionCallRefReturned(Expression* exp)
{
	Expression* lexp = nullptr, * rexp = nullptr;

	if (exp->mType == EX_PREFIX && exp->mToken == TK_BINARY_AND && exp->mLeft->mType == EX_CALL && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE && exp->mLeft->mDecType->mType != DT_TYPE_RVALUEREF)
	{
		lexp = AddFunctionCallRefReturned(exp->mLeft);

		// Returning a value object for pass by address
		// add a temporary variable

		//int	nindex = mLocalIndex++;

		Declaration* rtdec = exp->mLeft->mDecType;

		Declaration* vdec = AllocTempVar(rtdec);
#if 0
		Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE);

		vdec->mVarIndex = nindex;
		vdec->mBase = rtdec;
		vdec->mSize = rtdec->mSize;
#endif
		Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
		vexp->mDecType = rtdec;
		vexp->mDecValue = vdec;

		Expression* pex = new Expression(exp->mLocation, EX_INITIALIZATION);
		pex->mToken = TK_ASSIGN;
		pex->mLeft = vexp;
		pex->mRight = exp->mLeft;
		pex->mDecValue = nullptr;
		pex->mDecType = vdec->mBase;

		exp->mLeft = pex;

		if (rtdec->mDestructor)
		{
			Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
			texp->mToken = TK_BINARY_AND;
			texp->mLeft = vexp;
			texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
			texp->mDecType->mBase = vdec->mBase;
			texp->mDecType->mSize = 2;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = rtdec->mDestructor;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = texp;

			rexp = ConcatExpression(rexp, dexp);
		}
	}
	else if (exp->mType == EX_QUALIFY && exp->mLeft->mType == EX_CALL && exp->mLeft->mDecType->mType != DT_TYPE_REFERENCE && exp->mLeft->mDecType->mType != DT_TYPE_RVALUEREF)
	{
		lexp = AddFunctionCallRefReturned(exp->mLeft);

		// Returning a value object for pass by address
		// add a temporary variable

//		int	nindex = mLocalIndex++;

		Declaration* rtdec = exp->mLeft->mDecType;

		Declaration* vdec = AllocTempVar(rtdec);
#if 0
		Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE);

		vdec->mVarIndex = nindex;
		vdec->mBase = rtdec;
		vdec->mSize = rtdec->mSize;
#endif
		Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
		vexp->mDecType = rtdec;
		vexp->mDecValue = vdec;

		Expression* pex = new Expression(exp->mLocation, EX_INITIALIZATION);
		pex->mToken = TK_ASSIGN;
		pex->mLeft = vexp;
		pex->mRight = exp->mLeft;
		pex->mDecValue = nullptr;
		pex->mDecType = vdec->mBase;

		exp->mLeft = pex;

		if (rtdec->mDestructor)
		{
			Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
			texp->mToken = TK_BINARY_AND;
			texp->mLeft = vexp;
			texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
			texp->mDecType->mBase = vdec->mBase;
			texp->mDecType->mSize = 2;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = rtdec->mDestructor;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = texp;

			rexp = ConcatExpression(rexp, dexp);
		}
	}
	else if (exp->mType == EX_CALL)
	{
		lexp = AddFunctionCallRefReturned(exp->mLeft);
		if (exp->mRight)
		{
			Declaration* pdec = exp->mLeft->mDecType->mParams;
			Expression* rex = exp->mRight;

			while (pdec && rex)
			{
				Expression* pex = rex->mType == EX_LIST ? rex->mLeft : rex;
				if (rex->mType == EX_LIST)
					rex = rex->mRight;
				else
					rex = nullptr;

				rexp = ConcatExpression(rexp, AddFunctionCallRefReturned(pex));

				if (pdec->mBase->IsComplexStruct() && pex->mType == EX_CALL && pex->mDecType->mType == DT_TYPE_STRUCT)
				{
					Declaration* vdec = AllocTempVar(pex->mDecType);

					Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
					vexp->mDecType = pex->mDecType;
					vexp->mDecValue = vdec;

					Expression* cexp = new Expression(pex->mLocation, pex->mType);
					cexp->mDecType = pex->mDecType;
					cexp->mDecValue = pex->mDecValue;
					cexp->mLeft = pex->mLeft;
					cexp->mRight = pex->mRight;
					cexp->mToken = pex->mToken;

					pex->mType = EX_INITIALIZATION;
					pex->mToken = TK_ASSIGN;
					pex->mLeft = vexp;
					pex->mRight = cexp;
					pex->mDecValue = nullptr;
					pex->mDecType = vdec->mBase;

					if (vdec->mBase->mDestructor)
					{
						Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = vexp;
						texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = vdec->mBase;
						texp->mDecType->mSize = 2;

						Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
						cexp->mDecValue = vdec->mBase->mDestructor;
						cexp->mDecType = cexp->mDecValue->mBase;

						Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = texp;

						rexp = ConcatExpression(rexp, dexp);
					}
				}
				else if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && 
					(pex->mDecType->mType != DT_TYPE_REFERENCE && pex->mDecType->mType != DT_TYPE_RVALUEREF) && pex->mType == EX_CALL)
				{
					// Returning a value object for pass as reference
					// add a temporary variable

					Declaration* vdec = AllocTempVar(pex->mDecType);

					Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
					vexp->mDecType = pex->mDecType;
					vexp->mDecValue = vdec;

					Expression* cexp = new Expression(pex->mLocation, pex->mType);
					cexp->mDecType = pex->mDecType;
					cexp->mDecValue = pex->mDecValue;
					cexp->mLeft = pex->mLeft;
					cexp->mRight = pex->mRight;
					cexp->mToken = pex->mToken;

					pex->mType = EX_INITIALIZATION;
					pex->mToken = TK_ASSIGN;
					pex->mLeft = vexp;
					pex->mRight = cexp;
					pex->mDecValue = nullptr;
					pex->mDecType = vdec->mBase;

					if (vdec->mBase->mDestructor)
					{
						Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = vexp;
						texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = vdec->mBase;
						texp->mDecType->mSize = 2;

						Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
						cexp->mDecValue = vdec->mBase->mDestructor;
						cexp->mDecType = cexp->mDecValue->mBase;

						Expression * dexp = new Expression(mScanner->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = texp;

						rexp = ConcatExpression(rexp, dexp);
					}
				}
				else if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && pex->mType == EX_CONSTRUCT && pex->mRight->mType == EX_VARIABLE)
				{
					// A constructed object is passed by reference

					if (pex->mLeft->mRight)
					{
						rexp = ConcatExpression(rexp, pex->mLeft->mRight);
						pex->mLeft->mRight = nullptr;
					}					
				}
				else if ((pdec->mBase->mType == DT_TYPE_REFERENCE || pdec->mBase->mType == DT_TYPE_RVALUEREF) && pex->mType == EX_CONSTANT)
				{
					// A simple constant is passed by const ref
					if (pex->mDecValue->mType == DT_CONST_INTEGER || pex->mDecValue->mType == DT_CONST_FLOAT || pex->mDecValue->mType == DT_CONST_POINTER || pex->mDecValue->mType == DT_CONST_ADDRESS)
					{
						if (pdec->mType == DT_TYPE_REFERENCE && !(pdec->mBase->mFlags & DTF_CONST))
							mErrors->Error(pex->mLocation, EERR_INCOMPATIBLE_TYPES, "Can't pass constant as non constant reference");

						Declaration* vdec = AllocTempVar(pdec->mBase->mBase);

						Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
						vexp->mDecType = pdec->mBase->mBase;
						vexp->mDecValue = vdec;

						Expression* cexp = new Expression(pex->mLocation, pex->mType);
						cexp->mDecType = pex->mDecType;
						cexp->mDecValue = pex->mDecValue;
						cexp->mLeft = pex->mLeft;
						cexp->mRight = pex->mRight;
						cexp->mToken = pex->mToken;

						pex->mType = EX_INITIALIZATION;
						pex->mToken = TK_ASSIGN;
						pex->mLeft = vexp;
						pex->mRight = cexp;
						pex->mDecValue = nullptr;
						pex->mDecType = vdec->mBase;
					}
				}
				else if ((pdec->mBase->mType == DT_TYPE_REFERENCE && !pex->IsConstRef()) || (pdec->mBase->mType == DT_TYPE_RVALUEREF && !pex->IsLValue()))
				{
					if (pdec->mBase->mType == DT_TYPE_REFERENCE && !(pdec->mBase->mBase->mFlags & DTF_CONST))
						mErrors->Error(pex->mLocation, EERR_NOT_AN_LVALUE, "Can't pass rvalue as non constant reference");
					
					Declaration* vdec = AllocTempVar(pex->mDecType);

					Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
					vexp->mDecType = pex->mDecType;
					vexp->mDecValue = vdec;

					Expression* cexp = new Expression(pex->mLocation, pex->mType);
					cexp->mDecType = pex->mDecType;
					cexp->mDecValue = pex->mDecValue;
					cexp->mLeft = pex->mLeft;
					cexp->mRight = pex->mRight;
					cexp->mToken = pex->mToken;

					pex->mType = EX_INITIALIZATION;
					pex->mToken = TK_ASSIGN;
					pex->mLeft = vexp;
					pex->mRight = cexp;
					pex->mDecValue = nullptr;
					pex->mDecType = vdec->mBase;
				}
				else if (pex->mType == EX_CONSTRUCT && !pdec->IsReference())
				{
					pex->mLeft->mRight = nullptr;
				}

				pdec = pdec->mNext;
			}
		}
	}
	else if (exp->mType == EX_LOGICAL_AND || exp->mType == EX_LOGICAL_OR)
	{
		lexp = AddFunctionCallRefReturned(exp->mLeft);
		exp->mRight = CleanupExpression(exp->mRight);
	}
	else
	{
		if (exp->mLeft)
			lexp = AddFunctionCallRefReturned(exp->mLeft);
		if (exp->mRight)
			rexp = AddFunctionCallRefReturned(exp->mRight);
	}

	return ConcatExpression(lexp, rexp);
}

Expression* Parser::BuildVariableArrayInit(Expression * texp, Declaration* bpdec, Declaration* pdec, int boffset, int & offset)
{
	Expression* lexp = nullptr;

	if (boffset + pdec->mOffset != offset)
		mErrors->Error(pdec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Incomplete class initializer list");

	if (pdec->mType == DT_CONST_STRUCT)
	{
		boffset += offset;

		Declaration* edec = pdec->mParams;
		while (edec)
		{
			Expression * iexp = BuildVariableArrayInit(texp, bpdec, edec, boffset, offset);

			if (lexp)
			{
				Expression* nexp = new Expression(mScanner->mLocation, EX_LIST);
				nexp->mLeft = lexp;
				nexp->mRight = iexp;
				lexp = nexp;
			}
			else
				lexp = iexp;

			edec = edec->mNext;
		}
	}
	else if (pdec->mType == DT_CONST_CONSTRUCTOR)
	{
		Declaration* icdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		icdec->mBase = TheUnsignedIntTypeDeclaration;
		icdec->mInteger = offset / bpdec->mBase->mSize;

		Expression* icexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		icexp->mDecType = icdec->mBase;
		icexp->mDecValue = icdec;

		Expression* mexp = new Expression(mScanner->mLocation, EX_BINARY);
		mexp->mToken = TK_ADD;
		mexp->mLeft = texp;
		mexp->mRight = icexp;
		mexp->mDecType = bpdec;

		Expression* iexp = new Expression(pdec->mValue->mLocation, EX_CONSTRUCT);
		iexp->mLeft = new Expression(pdec->mValue->mLeft->mLocation, EX_LIST);
		iexp->mLeft->mLeft = new Expression(pdec->mValue->mLeft->mLeft->mLocation, EX_CALL);
		iexp->mLeft->mLeft->mLeft = pdec->mValue->mLeft->mLeft->mLeft;
		iexp->mLeft->mLeft->mDecType = pdec->mValue->mLeft->mLeft->mDecType;
		iexp->mLeft->mLeft->mRight = new Expression(pdec->mValue->mLeft->mLeft->mRight->mLocation, EX_LIST);
		iexp->mLeft->mLeft->mRight->mRight = pdec->mValue->mLeft->mLeft->mRight->mRight;
		iexp->mLeft->mLeft->mRight->mLeft = mexp;

		lexp = iexp;
		
		offset += bpdec->mBase->mSize;
	}
	else
		mErrors->Error(pdec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Invalid class initializer");

	return lexp;
}

Expression * Parser::BuildVariableInit(Expression* vexp, Expression* pexp)
{
	Declaration* mtype = vexp->mDecType;

	Declaration* fcons = mtype->mScope ? mtype->mScope->Lookup(mtype->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;

	if (mtype->mFlags & DTF_PURE_VIRTUAL)
		mErrors->Error(vexp->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", mtype->mIdent);

	if (fcons)
	{
		Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		cexp->mDecValue = fcons;
		cexp->mDecType = cexp->mDecValue->mBase;

		Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
		fexp->mLeft = cexp;
		fexp->mRight = pexp;

		Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
		texp->mToken = TK_BINARY_AND;
		texp->mLeft = vexp;
		texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
		texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
		texp->mDecType->mBase = mtype;
		texp->mDecType->mSize = 2;

		if (fexp->mRight)
		{
			Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
			lexp->mLeft = texp;
			lexp->mRight = fexp->mRight;
			fexp->mRight = lexp;
		}
		else
			fexp->mRight = texp;

		fexp = ResolveOverloadCall(fexp);

		Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

		nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
		nexp->mLeft->mLeft = fexp;

		nexp->mRight = vexp;
		nexp->mDecType = vexp->mDecType;

		return nexp;
	}
	else if (mtype->CanAssign(pexp->mDecType))
	{
		Expression * nexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
		nexp->mToken = TK_ASSIGN;
		nexp->mDecType = mtype;
		nexp->mLeft = vexp;
		nexp->mRight = pexp;

		return nexp;
	}
	else if (pexp)
		mErrors->Error(pexp->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", mtype->mIdent);

	return pexp;
}

void Parser::ParseVariableInit(Declaration* ndec, Expression* pexp)
{
	Declaration* fcons = ndec->mBase->mScope ? ndec->mBase->mScope->Lookup(ndec->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;

	if (!pexp)
	{
		Token	ctoken = mScanner->mToken == TK_OPEN_BRACE ? TK_CLOSE_BRACE : TK_CLOSE_PARENTHESIS;

		mScanner->NextToken();
		if (mScanner->mToken != ctoken)
		{
			pexp = ParseListExpression(false, fcons ? fcons->mBase->mParams->mNext : nullptr);
			ConsumeToken(ctoken);
		}
		else
			mScanner->NextToken();
	}

	if (ndec->mBase->mFlags & DTF_PURE_VIRTUAL)
		mErrors->Error(ndec->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", ndec->mIdent);

	if (pexp && pexp->mType != EX_LIST)
	{
		if (pexp->mDecType->IsSame(ndec->mBase))
			fcons = ndec->mBase->mCopyConstructor;
	}

	if (fcons)
	{
		Declaration* mtype = ndec->mBase->ToMutableType();

		Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
		vexp->mDecType = mtype;
		vexp->mDecValue = ndec;

		Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
		cexp->mDecValue = fcons;
		cexp->mDecType = cexp->mDecValue->mBase;

		Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
		fexp->mLeft = cexp;
		fexp->mRight = pexp;

		Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
		texp->mToken = TK_BINARY_AND;
		texp->mLeft = vexp;
		texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
		texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
		texp->mDecType->mBase = mtype;
		texp->mDecType->mSize = 2;

		if (fexp->mRight)
		{
			Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
			lexp->mLeft = texp;
			lexp->mRight = fexp->mRight;
			fexp->mRight = lexp;
		}
		else
			fexp->mRight = texp;

		fexp = ResolveOverloadCall(fexp);

		if ((fexp->mLeft->mDecValue->mFlags & DTF_CONSTEXPR) && ndec->mSection == mBSSection)
			ndec->mSection = mDataSection;

		Expression* dexp = nullptr;
		if (ndec->mBase->mDestructor)
		{
			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = ndec->mBase->mDestructor;
			cexp->mDecType = cexp->mDecValue->mBase;

			dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = texp;
		}

		Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

		nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
		nexp->mLeft->mLeft = fexp;
		nexp->mLeft->mRight = dexp;

		nexp->mRight = vexp;
		nexp->mDecType = vexp->mDecType;

		ndec->mValue = nexp;
	}
	else if (pexp && pexp->mType != EX_LIST && ndec->mBase->CanAssign(pexp->mDecType))
	{
		ndec->mValue = pexp;
	}
	else if (pexp)
		mErrors->Error(pexp->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", ndec->mIdent);
	else
		mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", ndec->mIdent);
}

Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool expression, bool member, Declaration* pthis, Declaration* ptempl)
{
	bool	definingType = false, destructor = false;
	uint64	storageFlags = 0, typeFlags = 0;
	Declaration* bdec;

	if (pdec)
	{
		bdec = pdec;
	}
	else
	{
		if (mScanner->mToken == TK_TYPEDEF)
		{
			definingType = true;
			variable = false;
			mScanner->NextToken();
		}
		else if (mScanner->mToken == TK_USING)
		{
			mScanner->NextToken();
			if (ConsumeTokenIf(TK_NAMESPACE))
			{
				Declaration* dec = ParseQualIdent(true);
				if (dec)
				{
					if (dec->mType == DT_NAMESPACE)
					{
						mScope->UseScope(dec->mScope);
					}
					else
					{
						mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a namespace");
						mErrors->Error(dec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
					}
				}

				return nullptr;
			}
			else if (ConsumeTokenIf(TK_ENUM))
			{
				Declaration* dec = ParseQualIdent(false);
				if (dec)
				{
					if (dec->mType == DT_TYPE_ENUM)
					{
						mScope->UseScope(dec->mScope);
					}
					else
					{
						mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not an enum");
						mErrors->Error(dec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
					}
				}

				return nullptr;
			}
			else
			{
				Declaration* dec;

				do {
					dec = ParseQualIdent(false);
					if (dec)
					{
						Declaration* pdec = mScope->Insert(dec->mIdent, dec);
						if (pdec && pdec != dec)
							mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate declaration", dec->mIdent);
					}
					else
						break;

				} while (ConsumeTokenIf(TK_COMMA));

				return dec;
			}
		}
		else
		{
			for (;;)
			{
				if (mScanner->mToken == TK_VIRTUAL)
				{
					storageFlags |= DTF_VIRTUAL;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_STATIC)
				{
					storageFlags |= DTF_STATIC;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_CONSTEXPR)
				{
					storageFlags |= DTF_CONSTEXPR | DTF_REQUEST_INLINE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_EXTERN)
				{
					storageFlags |= DTF_EXTERN;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_ZEROPAGE)
				{
					storageFlags |= DTF_ZEROPAGE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_STRIPED)
				{
					storageFlags |= DTF_STRIPED;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_NOINLINE)
				{
					storageFlags |= DTF_PREVENT_INLINE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_FORCEINLINE)
				{
					storageFlags |= DTF_FORCE_INLINE | DTF_REQUEST_INLINE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_INLINE)
				{
					storageFlags |= DTF_REQUEST_INLINE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_EXPORT)
				{
					storageFlags |= DTF_EXPORT;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_DYNSTACK)
				{
					storageFlags |= DTF_DYNSTACK;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_FASTCALL)
				{
					storageFlags |= DTF_FASTCALL;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_NATIVE)
				{
					storageFlags |= DTF_NATIVE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_INTERRUPT)
				{
					storageFlags |= DTF_INTERRUPT | DTF_NATIVE;
					mScanner->NextToken();
				}
				else if (mScanner->mToken == TK_HWINTERRUPT)
				{
					storageFlags |= DTF_INTERRUPT | DTF_HWINTERRUPT | DTF_NATIVE;
					mScanner->NextToken();
				}
				else
					break;
			}
		}

		if ((mCompilerOptions & COPT_CPLUSPLUS) && pthis && mScanner->mToken == TK_BINARY_NOT)
		{
			// Destructor declaration
			mScanner->NextToken();
			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* ident = mScanner->mTokenIdent;
				if (mTemplateScope)
				{
					Declaration* dec = mTemplateScope->Lookup(ident);
					if (dec)
						ident = dec->mIdent;
				}

				if (ident != pthis->mBase->mIdent)
					mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Wrong class name for destructor", pthis->mBase->mIdent);
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");

			Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

			if (ctdec->mParams)				
				mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Destructor can't have parameter");

			PrependThisArgument(ctdec, pthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL);
			cdec->mFlags |= storageFlags & (DTF_PREVENT_INLINE);

			cdec->mSection = mCodeSection;
			cdec->mBase->mFlags |= typeFlags;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mIdent = pthis->mBase->mIdent->PreMangle("~");
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			if (mScanner->mToken == TK_OPEN_BRACE)
			{
				cdec->mCompilerOptions = mCompilerOptions;
				cdec->mBase->mCompilerOptions = mCompilerOptions;

				cdec->mVarIndex = -1;

				cdec->mValue = ParseFunction(cdec->mBase);

				cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE;
				cdec->mNumVars = mLocalIndex;
			}

			return cdec;
		}
		if ((mCompilerOptions & COPT_CPLUSPLUS) && pthis && mScanner->mToken == TK_OPERATOR)
		{
			mScanner->NextToken();
			bdec = ParseBaseTypeDeclaration(typeFlags, false);

			Declaration* ctdec = ParseFunctionDeclaration(bdec);

			if (ctdec->mParams)
				mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Cast operators can't have parameter");

			Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			bthis->mFlags |= DTF_CONST | DTF_DEFINED;
			if (ConsumeTokenIf(TK_CONST))
				bthis->mBase = pthis->mBase->ToConstType();
			else
				bthis->mBase = pthis->mBase;
			bthis->mSize = 2;

			PrependThisArgument(ctdec, bthis);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);
			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL);
			cdec->mFlags |= storageFlags & (DTF_PREVENT_INLINE);

			cdec->mSection = mCodeSection;
			cdec->mBase->mFlags |= typeFlags;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			cdec->mIdent = Ident::Unique("(cast)");
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			if (mScanner->mToken == TK_OPEN_BRACE)
			{
				cdec->mCompilerOptions = mCompilerOptions;
				cdec->mBase->mCompilerOptions = mCompilerOptions;

				cdec->mVarIndex = -1;

				cdec->mValue = ParseFunction(cdec->mBase);

				cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE;
				cdec->mNumVars = mLocalIndex;
			}

			return cdec;
		}

		bdec = ParseBaseTypeDeclaration(typeFlags, false, ptempl);
	}

	Declaration* rdec = nullptr, * ldec = nullptr;

	if (mCompilerOptions & COPT_CPLUSPLUS)
	{
		if (bdec && pthis && bdec == pthis->mBase && mScanner->mToken == TK_OPEN_PARENTHESIS)
		{
			Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

			Declaration* cdec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);

			PrependThisArgument(ctdec, pthis);

			cdec->mBase = ctdec;

			cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
			cdec->mFlags |= storageFlags & (DTF_INLINE | DTF_CONSTEXPR | DTF_PREVENT_INLINE);

			cdec->mSection = mCodeSection;
			cdec->mBase->mFlags |= typeFlags;

			if (mCompilerOptions & COPT_NATIVE)
				cdec->mFlags |= DTF_NATIVE;

			Declaration* pdec = pthis->mBase->mScope ? pthis->mBase->mScope->Lookup(pthis->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;
			if (pdec)
			{
				while (pdec && !cdec->mBase->IsSameParams(pdec->mBase))
					pdec = pdec->mNext;
			}

			Declaration* dec = cdec;

			if (pdec)
			{
				if (!cdec->mBase->IsSame(pdec->mBase))
					mErrors->Error(cdec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs");
				else if (cdec->mFlags & ~pdec->mFlags & (DTF_HWINTERRUPT | DTF_INTERRUPT | DTF_FASTCALL | DTF_NATIVE))
					mErrors->Error(cdec->mLocation, EERR_DECLARATION_DIFFERS, "Function call type declaration differs");
				else
				{
					// 
					// Take parameter names from new declaration
					//
					Declaration* npdec = cdec->mBase->mParams, * ppdec = pdec->mBase->mParams;
					while (npdec && ppdec)
					{
						if (npdec->mIdent)
						{
							ppdec->mIdent = npdec->mIdent;
							ppdec->mQualIdent = npdec->mQualIdent;
						}
						npdec = npdec->mNext;
						ppdec = ppdec->mNext;
					}
				}

				dec = pdec;
				if (!(pdec->mFlags & DTF_DEFINED))
					cdec = pdec;
			}

			cdec->mIdent = pthis->mBase->mIdent->PreMangle("+");
			cdec->mQualIdent = pthis->mBase->mScope->Mangle(cdec->mIdent);

			// Initializer list
			if (mScanner->mToken == TK_COLON)
			{
				BuildMemberConstructor(pthis, cdec);
			}

			if (mScanner->mToken == TK_OPEN_BRACE)
			{
				if (cdec->mFlags & DTF_DEFINED)
				{
					mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body");
					mErrors->Error(cdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
				}

				cdec->mCompilerOptions = mCompilerOptions;
				cdec->mBase->mCompilerOptions = mCompilerOptions;

				cdec->mVarIndex = -1;

				cdec->mValue = ParseFunction(cdec->mBase);

				cdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE;
				cdec->mNumVars = mLocalIndex;

				if (ptempl)
					PrependMemberConstructor(pthis, cdec);
			}

			return dec;
		}

		if (bdec && bdec->mType == DT_TYPE_STRUCT && ConsumeTokenIf(TK_COLCOLON))
		{
			if (mScanner->mToken == TK_IDENT)
			{
				if (mScanner->mTokenIdent == bdec->mIdent)
				{
					mScanner->NextToken();

					Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

					Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
					bthis->mFlags |= DTF_CONST | DTF_DEFINED;
					if (ConsumeTokenIf(TK_CONST))
						bthis->mBase = bdec->ToConstType();
					else
						bthis->mBase = bdec;
					bthis->mSize = 2;

					PrependThisArgument(ctdec, bthis);

					Declaration* cdec = bdec->mScope->Lookup(bdec->mIdent->PreMangle("+"), SLEVEL_CLASS);
					if (cdec)
					{
						while (cdec && !cdec->mBase->IsSameParams(ctdec))
							cdec = cdec->mNext;
					}

					if (cdec)
					{
						cdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR);

						// Initializer list
						if (mScanner->mToken == TK_COLON)
						{
							BuildMemberConstructor(bthis, cdec);
						}

						if (mScanner->mToken == TK_OPEN_BRACE)
						{
							// 
							// Take parameter names from new declaration
							//
							Declaration* npdec = ctdec->mParams, * ppdec = cdec->mBase->mParams;
							while (npdec && ppdec)
							{
								if (npdec->mIdent)
								{
									ppdec->mIdent = npdec->mIdent;
									ppdec->mQualIdent = npdec->mQualIdent;
								}
								npdec = npdec->mNext;
								ppdec = ppdec->mNext;
							}

							if (cdec->mFlags & DTF_DEFINED)
							{
								mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body");
								mErrors->Error(cdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
							}

							cdec->mCompilerOptions = mCompilerOptions;
							cdec->mBase->mCompilerOptions = mCompilerOptions;

							cdec->mVarIndex = -1;

							cdec->mValue = ParseFunction(cdec->mBase);

							cdec->mFlags |= DTF_DEFINED;
							cdec->mNumVars = mLocalIndex;

							PrependMemberConstructor(bthis, cdec);
						}

						return cdec;
					}
					else
					{
						mErrors->Error(bdec->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching constructor");
						return bdec;
					}
				}
				else
				{
					Declaration* mdec = bdec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS);
					if (mdec)
						bdec = mdec;
					else
						mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Member not found", mScanner->mTokenIdent);
					mScanner->NextToken();
				}
			}

			if (ConsumeTokenIf(TK_BINARY_NOT))
			{
				if (mScanner->mToken == TK_IDENT)
				{
					if (mScanner->mTokenIdent != bdec->mIdent)
						mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Wrong class name for destructor", bdec->mIdent);
					mScanner->NextToken();
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");

				Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

				if (ctdec->mParams)
					mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Destructor can't have parameter");

				if (bdec->mDestructor)
				{
					bdec->mDestructor->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR);

					Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
					bthis->mFlags |= DTF_CONST | DTF_DEFINED;
					bthis->mBase = bdec;
					bthis->mSize = 2;

					bdec->mDestructor->mCompilerOptions = mCompilerOptions;
					bdec->mDestructor->mBase->mCompilerOptions = mCompilerOptions;

					bdec->mDestructor->mVarIndex = -1;

					bdec->mDestructor->mValue = ParseFunction(bdec->mDestructor->mBase);

					bdec->mDestructor->mFlags |= DTF_DEFINED;
					bdec->mDestructor->mNumVars = mLocalIndex;

					AppendMemberDestructor(bthis);
				}
				else
					mErrors->Error(ctdec->mLocation, EERR_DUPLICATE_DEFINITION, "Destructor not declared", bdec->mIdent);

				return bdec->mDestructor;
			}
			else if (ConsumeTokenIf(TK_OPERATOR))
			{
				Declaration* tdec = ParseBaseTypeDeclaration(0, true);

				Declaration* ctdec = ParseFunctionDeclaration(tdec);

				if (ctdec->mParams)
					mErrors->Error(ctdec->mLocation, EERR_WRONG_PARAMETER, "Cast operators can't have parameter");

				Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
				bthis->mFlags |= DTF_CONST | DTF_DEFINED;
				if (ConsumeTokenIf(TK_CONST))
					bthis->mBase = bdec->ToConstType();
				else
					bthis->mBase = bdec;
				bthis->mSize = 2;

				PrependThisArgument(ctdec, bthis);

				Declaration* fdec = bdec->mScope->Lookup(Ident::Unique("(cast)"));
				while (fdec && !fdec->mBase->IsSame(ctdec))
					fdec = fdec->mNext;

				if (fdec)
				{
					fdec->mCompilerOptions = mCompilerOptions;
					fdec->mBase->mCompilerOptions = mCompilerOptions;

					fdec->mVarIndex = -1;

					fdec->mValue = ParseFunction(fdec->mBase);

					fdec->mFlags |= DTF_DEFINED;
					fdec->mNumVars = mLocalIndex;
				}
				else
					mErrors->Error(ctdec->mLocation, EERR_DUPLICATE_DEFINITION, "Cast operator not declared", tdec->mIdent);

				return fdec;
			}
		}
	}

	for (;;)
	{
		Declaration* ndec = ParsePostfixDeclaration();

		ndec = ReverseDeclaration(ndec, bdec);

		if (storageFlags & DTF_STRIPED)
			ndec = ndec->ToStriped(mErrors);

		Declaration* npdec = ndec;

		if (npdec->mBase->mType == DT_TYPE_POINTER)
			npdec = npdec->mBase;

		// Make room for return value pointer on struct return
		if (npdec->mBase->mType == DT_TYPE_FUNCTION && npdec->mBase->mBase->IsComplexStruct())
		{
			Declaration* pdec = npdec->mBase->mParams;
			while (pdec)
			{
				pdec->mVarIndex += 2;
				pdec = pdec->mNext;
			}
		}
		
		if (npdec->mBase->mType == DT_TYPE_FUNCTION)
			npdec->mBase->mFlags |= storageFlags & (DTF_INTERRUPT | DTF_NATIVE | DTF_FASTCALL | DTF_VIRTUAL);

		if (definingType)
		{
			if (ndec->mIdent)
			{
				Declaration* pdec = mScope->Insert(ndec->mIdent, ndec->mBase);
				if (pdec && pdec != ndec->mBase)
					mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate type declaration", ndec->mIdent);
			}
		}
		else
		{
			if (ptempl)
				ptempl->mBase = ndec;

			if (ptempl && mTemplateScope && ndec->mIdent)
			{
				if (!strstr(ndec->mQualIdent->mString, mTemplateScope->mName->mString))
				{
					ndec->mIdent = ndec->mIdent->Mangle(mTemplateScope->mName->mString);
					ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString);
				}
			}

			if (ndec->mBase->mType == DT_TYPE_FUNCTION)
			{					
				ndec->mBase->mClass = pthis;

				if (pthis && !(storageFlags & DTF_STATIC))
				{
					if (ConsumeTokenIf(TK_CONST))
						PrependThisArgument(ndec->mBase, pthis->mBase->ToConstType()->BuildConstPointer(ndec->mLocation));
					else
						PrependThisArgument(ndec->mBase, pthis);
					ndec->mBase->mFlags |= DTF_FUNC_THIS;
				}
			}


			if (variable)
			{
				if (storageFlags & DTF_CONSTEXPR)
					ndec->mBase = ndec->mBase->ToConstType();

				ndec->mFlags |= storageFlags;
				ndec->mFlags |= ndec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

				if (ndec->mBase->mType == DT_TYPE_FUNCTION)
				{
					ndec->mType = DT_CONST_FUNCTION;
					ndec->mSection = mCodeSection;
					ndec->mBase->mFlags |= typeFlags;

					if (mCompilerOptions & COPT_NATIVE)
						ndec->mFlags |= DTF_NATIVE;

					Declaration* ntdec = FunctionAutoParamsToTemplate(ndec);
					if (ntdec)
						return ntdec;
				}

				if (ndec->mIdent)
				{
					Declaration* pdec;
					
					if (storageFlags & DTF_ZEROPAGE)
					{
						if (ndec->mType == DT_VARIABLE)
							ndec->mSection = mCompilationUnits->mSectionZeroPage;
						else
							mErrors->Error(ndec->mLocation, ERRR_INVALID_STORAGE_TYPE, "Invalid storage type", ndec->mIdent);
					}

					if (mScope->mLevel < SLEVEL_FUNCTION && !(storageFlags & DTF_STATIC))
					{
						pdec = mCompilationUnits->mScope->Insert(ndec->mQualIdent, ndec);

						if (mScope->Mangle(ndec->mIdent) == ndec->mQualIdent)
						{
							Declaration* ldec = mScope->Insert(ndec->mIdent, pdec ? pdec : ndec);
#if 0
							if (ldec && ldec->mTemplate && mTemplateScope)
							{
								ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString);
							}
							else 
#endif
								
							if (ldec && ldec != pdec)
							{
								mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition");
								mErrors->Error(ldec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
							}
						}
						else if (ptempl && mTemplateScope && pthis)
						{
						}
						else if (!pdec)
							mErrors->Error(ndec->mLocation, EERR_OBJECT_NOT_FOUND, "Object not declarared in scope", ndec->mQualIdent);

					}
					else
						pdec = mScope->Insert(ndec->mIdent, ndec);

					if (pdec)
					{
						if (pdec->mType == DT_CONST_FUNCTION && ndec->mBase->mType == DT_TYPE_FUNCTION)
						{
							if (pdec->mBase->mFlags & DTF_FUNC_THIS)
							{
								if (!(ndec->mBase->mFlags & DTF_FUNC_THIS))
								{
									Declaration* adec = pdec->mBase->mParams->Clone();
									adec->mNext = ndec->mBase->mParams;

									if (ConsumeTokenIf(TK_CONST))
									{
										if (!(adec->mBase->mBase->mFlags & DTF_CONST))
											adec->mBase = adec->mBase->mBase->ToConstType()->BuildConstPointer(adec->mLocation);
									}
									else
									{
										if (adec->mBase->mBase->mFlags & DTF_CONST)
											adec->mBase = adec->mBase->mBase->ToMutableType()->BuildConstPointer(adec->mLocation);
									}

									Declaration* p = adec->mBase->mParams;
									while (p)
									{
										p->mVarIndex += 2;
										p = p->mNext;
									}

									ndec->mBase->mParams = adec;

									ndec->mBase->mFlags |= DTF_FUNC_THIS;
								}
							}
							else if (ndec->mBase->mFlags & DTF_FUNC_THIS)
							{
								if (pdec->mBase->mParams)
									ndec->mBase->mParams = pdec->mBase->mParams->Clone();
								else
									ndec->mBase->mParams = nullptr;
								ndec->mBase->mFlags &= ~DTF_FUNC_THIS;
							}

							if (mCompilerOptions & COPT_CPLUSPLUS)
							{
								Declaration* pcdec = nullptr;

								while (pdec && !ndec->mBase->IsSameParams(pdec->mBase))
								{
									pcdec = pdec;
									pdec = pdec->mNext;
								}

								if (!pdec)
								{
									if (!pthis && (ndec->mBase->mFlags & DTF_FUNC_THIS))
										mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent);

									pcdec->mNext = ndec;
								}
							}

							if (pdec)
							{
								if (!ndec->mBase->IsSame(pdec->mBase) && !(ndec->mBase->mBase->mType == DT_TYPE_AUTO && ndec->mBase->IsSameParams(pdec->mBase)))
								{
									ndec->mBase->IsSameParams(pdec->mBase);
									ndec->mBase->IsSame(pdec->mBase);
									mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function declaration differs", ndec->mIdent);
								}
								else if (ndec->mFlags & ~pdec->mFlags & (DTF_HWINTERRUPT | DTF_INTERRUPT | DTF_FASTCALL | DTF_NATIVE))
									mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Function call type declaration differs", ndec->mIdent);
								else
								{
									// 
									// Take parameter names from new declaration
									//
									Declaration* npdec = ndec->mBase->mParams, * ppdec = pdec->mBase->mParams;
									while (npdec && ppdec)
									{
										if (npdec->mIdent)
										{
											ppdec->mIdent = npdec->mIdent;
											ppdec->mQualIdent = npdec->mQualIdent;
										}
										ppdec->mBase = npdec->mBase;

										npdec = npdec->mNext;
										ppdec = ppdec->mNext;
									}
								}

								pdec->mFlags |= ndec->mFlags & (DTF_REQUEST_INLINE | DTF_PREVENT_INLINE | DTF_FORCE_INLINE);

								ndec = pdec;
							}
						}
						else if (ndec->mFlags & DTF_EXTERN)
						{
							if (!ndec->mBase->IsSame(pdec->mBase))
							{
								if (ndec->mBase->mType == DT_TYPE_ARRAY && pdec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase) && ndec->mBase->mSize == 0)
									;
								else if (ndec->mBase->mType == DT_TYPE_POINTER && pdec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase))
									;
								else
								{
									mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Variable declaration differs", ndec->mIdent);
									mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
								}
							}

							pdec->mFlags |= ndec->mFlags & DTF_ZEROPAGE;

							ndec = pdec;
						}
						else if (pdec->mFlags & DTF_EXTERN)
						{
							if (!ndec->mBase->IsSame(pdec->mBase))
							{
								if (ndec->mBase->mType == DT_TYPE_ARRAY && pdec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase))
								{
									pdec->mBase = ndec->mBase;
								}
								else if (pdec->mBase->mType == DT_TYPE_POINTER && ndec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase))
								{
									pdec->mBase = ndec->mBase;
								}
								else
									mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Variable declaration differs", ndec->mIdent);
							}
							else
								pdec->mBase = ndec->mBase;

							if (!(ndec->mFlags & DTF_EXTERN))
							{
								pdec->mFlags &= ~DTF_EXTERN;
								pdec->mSection = ndec->mSection;
								pdec->mSize = ndec->mSize;
							}

							pdec->mFlags |= ndec->mFlags & DTF_ZEROPAGE;

							ndec = pdec;
						}
						else if ((mCompilerOptions & COPT_CPLUSPLUS) || mScope->mLevel >= SLEVEL_FUNCTION)
						{
							mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate variable declaration", ndec->mIdent);
							mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
						}
						else
						{
							if (!ndec->mBase->IsSame(pdec->mBase))
							{
								if (ndec->mBase->mType == DT_TYPE_ARRAY && pdec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase) && pdec->mBase->mSize == 0)
									pdec->mBase->mSize = ndec->mBase->mSize;
								else if (pdec->mBase->mType == DT_TYPE_POINTER && ndec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase))
								{
									pdec->mBase = ndec->mBase;
								}
								else
								{
									mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Variable declaration differs", ndec->mIdent);
									mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
								}

							}

							pdec->mSection = ndec->mSection;

							pdec->mFlags |= ndec->mFlags & DTF_ZEROPAGE;

							if (pdec->mValue)
							{
								mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate variable declaration", ndec->mIdent);
								mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
							}

							ndec = pdec;

						}
					}
				}

				if (mScope->mLevel < SLEVEL_FUNCTION || (ndec->mFlags & DTF_STATIC))
				{
					if (ndec->mSize >= 256)
						ndec->mAlignment = ((ndec->mAlignment - 1) | (ndec->mBase->Alignment() - 1)) + 1;

					ndec->mFlags |= DTF_GLOBAL;
					ndec->mVarIndex = -1;
				}
				else
					ndec->mVarIndex = mLocalIndex++;
			}
			else if (pthis)
			{
				ndec->mFlags |= storageFlags & (DTF_STATIC | DTF_PREVENT_INLINE | DTF_FORCE_INLINE);
				if (storageFlags & DTF_CONSTEXPR)
				{
					ndec->mFlags |= DTF_CONSTEXPR;
					ndec->mBase = ndec->mBase->ToConstType();
				}
			}

			ndec->mOffset = 0;

			if (rdec)
				ldec->mNext = ndec;
			else
				rdec = ndec;
			ldec = ndec;
//			ndec->mNext = nullptr;

			if (member && ConsumeTokenIf(TK_COLON))
			{
				Expression* exp = ParseRExpression();
				if (!ndec->mBase->IsIntegerType())
					mErrors->Error(exp->mLocation, EERR_INVALID_BITFIELD, "Invalid bitfield for non integer type");
				else if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType() && exp->mDecValue->mType == DT_CONST_INTEGER)
					ndec->mBits = uint8(exp->mDecValue->mInteger);
				else
					mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Constant integer expression expected");
			}

			else if (mScanner->mToken == TK_OPEN_PARENTHESIS && (mCompilerOptions & COPT_CPLUSPLUS))
			{
				ParseVariableInit(ndec);
			}
			else if (mScanner->mToken == TK_OPEN_BRACE && (mCompilerOptions & COPT_CPLUSPLUS) && ndec->mType == DT_VARIABLE && !pthis && !(storageFlags & DTF_EXTERN))
			{
				ParseVariableInit(ndec);
			}
			else
			{
				if (ConsumeTokenIf(TK_ASSIGN))
				{
					if (pthis && ndec->mBase->mType == DT_TYPE_FUNCTION && mScanner->mToken == TK_INTEGER && mScanner->mTokenInteger == 0)
					{
						mScanner->NextToken();
						ndec->mValue = new Expression(mScanner->mLocation, EX_ASSUME);
						Declaration	*	fdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
						fdec->mBase = TheBoolTypeDeclaration;
						fdec->mInteger = 0;
						ndec->mValue->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						ndec->mValue->mLeft->mDecValue = fdec;
						ndec->mValue->mLeft->mDecType = fdec->mBase;
						ndec->mFlags |= DTF_DEFINED | DTF_PURE_VIRTUAL;
					}
					else
					{
						if (member || (ndec->mFlags & (DTF_STATIC | DTF_GLOBAL)))
							ndec->mValue = ParseConstInitExpression(ndec->mBase);
						else
						{
							Expression* vexp = new Expression(ndec->mLocation, EX_VARIABLE);
							vexp->mDecType = ndec->mBase;
							vexp->mDecValue = ndec;

							ndec->mValue = ParseVarInitExpression(vexp);

							if (ndec->mBase->mType == DT_TYPE_AUTO)
							{
								ndec->mBase = ndec->mBase->DeduceAuto(ndec->mValue->mDecType);
								if (ndec->mValue->mDecType->IsSame(ndec->mBase))
								{
									vexp->mDecType = ndec->mBase;
									Expression* exp = CopyElision(vexp, ndec->mValue);
									if (exp)
										ndec->mValue = exp;
								}
							}
						}

						ndec->mBase = ndec->mBase->DeduceAuto(ndec->mValue->mDecType);

						if (ndec->mFlags & (DTF_GLOBAL | DTF_STATIC))
						{
							if (ndec->mFlags & DTF_ZEROPAGE)
								;
							else
								ndec->mSection = mDataSection;
						}
						ndec->mSize = ndec->mBase->mSize;
					}
				}

				if ((mCompilerOptions & COPT_CPLUSPLUS) && ndec->mType == DT_VARIABLE && !pthis && !(storageFlags & DTF_EXTERN))
				{
					if (ndec->mValue && ndec->mValue->mType == EX_CONSTRUCT && ndec->mValue->mRight && ndec->mValue->mRight->mDecValue == ndec)
					{
					}
					else
					{
						// Find default constructor

						Declaration* bdec = ndec->mBase;
						while (bdec && bdec->mType == DT_TYPE_ARRAY)
							bdec = bdec->mBase;

						if (bdec->mFlags & DTF_PURE_VIRTUAL)
							mErrors->Error(ndec->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", ndec->mIdent);

						if (bdec && bdec->mDefaultConstructor)
						{
							bdec = bdec->ToMutableType();

							Expression* vexp = new Expression(ndec->mLocation, EX_VARIABLE);
							vexp->mDecType = ndec->mBase;
							vexp->mDecValue = ndec;

							Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
							texp->mToken = TK_BINARY_AND;
							texp->mLeft = vexp;
							texp->mDecType = bdec->BuildPointer(mScanner->mLocation);

							if (ndec->mBase->mType == DT_TYPE_STRUCT)
							{
								if (ndec->mValue)
								{
									ParseVariableInit(ndec, ndec->mValue);
								}
								else
								{
									Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
									cexp->mDecValue = bdec->mDefaultConstructor;
									cexp->mDecType = cexp->mDecValue->mBase;

									Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
									fexp->mLeft = cexp;
									fexp->mRight = texp;

									if (bdec->mDefaultConstructor->mFlags & DTF_CONSTEXPR)
										ndec->mSection = mDataSection;

									Expression* dexp = nullptr;
									if (ndec->mBase->mDestructor)
									{
										Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
										cexp->mDecValue = ndec->mBase->mDestructor;
										cexp->mDecType = cexp->mDecValue->mBase;

										dexp = new Expression(mScanner->mLocation, EX_CALL);
										dexp->mLeft = cexp;
										dexp->mRight = texp;
									}

									Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

									nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
									nexp->mLeft->mLeft = fexp;
									nexp->mLeft->mRight = dexp;

									nexp->mRight = vexp;
									nexp->mDecType = vexp->mDecType;

									ndec->mValue = nexp;
								}
							}
							else if (ndec->mValue)
							{
								Expression* lexp = nullptr;

								Declaration* bpdec = bdec->BuildPointer(mScanner->mLocation);

								if (ndec->mValue->mType == EX_CONSTANT)
								{
									int offset = 0;
									lexp = BuildVariableArrayInit(texp, bpdec, ndec->mValue->mDecValue, 0, offset);

									if (offset != ndec->mSize)
										mErrors->Error(pdec->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Incomplete class initializer list");

									while (texp->mDecType->mBase->mType == DT_TYPE_ARRAY)
									{
										Expression* iexp = new Expression(vexp->mLocation, EX_PREFIX);
										iexp->mToken = TK_MUL;
										iexp->mLeft = texp;
										iexp->mDecType = texp->mDecType->mBase;
										texp = iexp;
									}

									texp->mDecType = bpdec;

									//texp->mDecType = bdec->BuildPointer(vexp->mLocation);

									Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
									ncdec->mBase = TheUnsignedIntTypeDeclaration;
									ncdec->mInteger = ndec->mSize / bdec->mSize;

									Expression* ncexp = new Expression(mScanner->mLocation, EX_CONSTANT);
									ncexp->mDecType = ncdec->mBase;
									ncexp->mDecValue = ncdec;

									Expression* dexp = nullptr;
									if (bdec->mDestructor)
									{
										Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
										cexp->mDecValue = bdec->mVectorDestructor;
										cexp->mDecType = cexp->mDecValue->mBase;

										dexp = new Expression(mScanner->mLocation, EX_CALL);
										dexp->mLeft = cexp;
										dexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
										dexp->mRight->mLeft = texp;
										dexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY);
										dexp->mRight->mRight->mToken = TK_ADD;
										dexp->mRight->mRight->mLeft = texp;
										dexp->mRight->mRight->mDecType = texp->mDecType;
										dexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
										dexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
										dexp->mRight->mRight->mRight->mDecValue = ncdec;
									}

									Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

									nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
									nexp->mLeft->mLeft = lexp;
									nexp->mLeft->mRight = dexp;

									nexp->mRight = vexp;
									nexp->mDecType = vexp->mDecType;

									ndec->mValue = nexp;
									ndec->mFlags |= DTF_VAR_ALIASING;
								}
								else if (member || (ndec->mFlags & (DTF_STATIC | DTF_GLOBAL)))
									mErrors->Error(ndec->mValue->mLocation, EERR_INVALID_CLASS_INITIALIZER, "Invalid class initializer list");
							}
							else
							{
								Declaration* bpdec = bdec->BuildPointer(mScanner->mLocation);

								while (texp->mDecType->mBase->mType == DT_TYPE_ARRAY)
								{
									Expression* iexp = new Expression(vexp->mLocation, EX_PREFIX);
									iexp->mToken = TK_MUL;
									iexp->mLeft = texp;
									iexp->mDecType = texp->mDecType->mBase;
									texp = iexp;
								}

								texp->mDecType = bpdec;

								Declaration* ncdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								ncdec->mBase = TheUnsignedIntTypeDeclaration;
								ncdec->mInteger = ndec->mSize / bdec->mSize;

								Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
								cexp->mDecValue = bdec->mVectorConstructor;
								cexp->mDecType = cexp->mDecValue->mBase;

								Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
								fexp->mLeft = cexp;

								fexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
								fexp->mRight->mLeft = texp;
								fexp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY);
								fexp->mRight->mRight->mToken = TK_ADD;
								fexp->mRight->mRight->mLeft = texp;
								fexp->mRight->mRight->mDecType = texp->mDecType;
								fexp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								fexp->mRight->mRight->mRight->mDecType = ncdec->mBase;
								fexp->mRight->mRight->mRight->mDecValue = ncdec;

								Expression* dexp = nullptr;
								if (bdec->mDestructor)
								{
									Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
									cexp->mDecValue = bdec->mVectorDestructor;
									cexp->mDecType = cexp->mDecValue->mBase;

									dexp = new Expression(mScanner->mLocation, EX_CALL);
									dexp->mLeft = cexp;
									dexp->mRight = fexp->mRight;
								}

								Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

								nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
								nexp->mLeft->mLeft = fexp;
								nexp->mLeft->mRight = dexp;

								nexp->mRight = vexp;
								nexp->mDecType = vexp->mDecType;

								ndec->mValue = nexp;
							}
						}
						else if (bdec && bdec->mDestructor)
							mErrors->Error(ndec->mLocation, EERR_NO_DEFAULT_CONSTRUCTOR, "No default constructor for class", ndec->mBase->mIdent);
					}
				}
			}

			if (storageFlags & DTF_EXPORT)
			{
				mCompilationUnits->AddReferenced(ndec);
			}
		}

		if (mScanner->mToken == TK_COMMA)
			mScanner->NextToken();
		else if (mScanner->mToken == TK_OPEN_BRACE)
		{
			if (ndec->mBase->mType == DT_TYPE_FUNCTION)
			{
				if (!(ndec->mFlags & DTF_PLACED))
					ndec->mSection = mCodeSection;

				if ((ndec->mFlags & DTF_DEFINED) && !(ndec->mFlags & DTF_REQUEST_INLINE))
				{
					mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition", ndec->mQualIdent);
					mErrors->Error(ndec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
				}

				ndec->mCompilerOptions = mCompilerOptions;
				ndec->mBase->mCompilerOptions = mCompilerOptions;

				ndec->mVarIndex = -1;

				mFunction = ndec;
				ndec->mValue = ParseFunction(ndec->mBase);
				mFunction = nullptr;

				if (pthis && !(storageFlags & DTF_PREVENT_INLINE))
					ndec->mFlags |= DTF_REQUEST_INLINE;

				ndec->mFlags |= DTF_DEFINED;
				ndec->mNumVars = mLocalIndex;

			}
			return rdec;
		}
		else
		{
			if (!expression && mScanner->mToken != TK_SEMICOLON)
				mErrors->Error(mScanner->mLocation, ERRR_SEMICOLON_EXPECTED, "Semicolon expected");

			return rdec;
		}
	}

	return rdec;
}

Expression* Parser::ParseDeclarationExpression(Declaration * pdec)
{
	Declaration* dec;
	Expression* exp = nullptr, * rexp = nullptr;

	dec = ParseDeclaration(pdec, true, true, false);
	if (dec->mType == DT_ANON && dec->mNext == 0)
	{
		exp = new Expression(dec->mLocation, EX_TYPE);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;
	}
	else
	{
		while (dec)
		{
			Expression* nexp;

			if (dec->mValue && !(dec->mFlags & DTF_GLOBAL))
			{
				if (dec->mValue->mType == EX_INITIALIZATION || dec->mValue->mType == EX_LIST)
				{
					nexp = dec->mValue;
				}
				else if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mValue->mType == EX_CONSTRUCT)
				{
					nexp = dec->mValue;

					Expression* vdec = nexp->mRight;
					if (vdec->mDecValue != dec)
					{
						vdec->mDecValue = dec;
					}
				}
				else if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mBase->mDestructor)
				{
					Expression* vexp = new Expression(dec->mLocation, EX_VARIABLE);
					vexp->mDecType = dec->mBase;
					vexp->mDecValue = dec;

					Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
					texp->mToken = TK_BINARY_AND;
					texp->mLeft = vexp;
					texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
					texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
					texp->mDecType->mBase = dec->mBase;
					texp->mDecType->mSize = 2;

					Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					cexp->mDecValue = dec->mBase->mDestructor;
					cexp->mDecType = cexp->mDecValue->mBase;

					Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
					dexp->mLeft = cexp;
					dexp->mRight = texp;

					Expression* aexp;
					
					Declaration* fcons = dec->mBase->mScope->Lookup(dec->mBase->mIdent->PreMangle("+"));

					if (fcons && !(dec->mValue->mType == EX_CALL && dec->mValue->mDecType->mType == DT_TYPE_STRUCT))
					{

						Expression* cexp = new Expression(dec->mLocation, EX_CONSTANT);
						cexp->mDecValue = fcons;
						cexp->mDecType = cexp->mDecValue->mBase;

						aexp = new Expression(mScanner->mLocation, EX_CALL);
						aexp->mLeft = cexp;
						aexp->mRight = new Expression(dec->mLocation, EX_LIST);
						aexp->mRight->mLeft = texp;
						aexp->mRight->mRight = dec->mValue;

						ResolveOverloadCall(aexp);
					}
					else
					{
						aexp = new Expression(dec->mValue->mLocation, EX_INITIALIZATION);
						aexp->mToken = TK_ASSIGN;
						aexp->mLeft = new Expression(dec->mLocation, EX_VARIABLE);
						aexp->mLeft->mDecValue = dec;
						aexp->mLeft->mDecType = dec->mBase;
						aexp->mDecType = aexp->mLeft->mDecType;
						aexp->mRight = dec->mValue;
					}

					nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

					nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
					nexp->mLeft->mLeft = aexp;
					nexp->mLeft->mRight = dexp;
					nexp->mRight = vexp;
					nexp->mDecType = vexp->mDecType;
				}
				else
				{
					nexp = new Expression(dec->mValue->mLocation, EX_INITIALIZATION);
					nexp->mToken = TK_ASSIGN;
					nexp->mLeft = new Expression(dec->mLocation, EX_VARIABLE);
					nexp->mLeft->mDecValue = dec;
					nexp->mLeft->mDecType = dec->mBase;
					nexp->mDecType = nexp->mLeft->mDecType;

					nexp->mRight = dec->mValue;
				}
			}
			else
			{
				nexp = new Expression(dec->mLocation, EX_VARIABLE);
				nexp->mDecValue = dec;
				nexp->mDecType = dec->mBase;
			}

			if (!exp)
				exp = nexp;
			else
			{
				if (!rexp)
				{
					rexp = new Expression(nexp->mLocation, EX_SEQUENCE);
					rexp->mLeft = exp;
					exp = rexp;
				}
				rexp->mRight = new Expression(nexp->mLocation, EX_SEQUENCE);
				rexp = rexp->mRight;
				rexp->mLeft = nexp;
			}

			dec = dec->mNext;
		}
	}

	return exp;
}

Declaration* Parser::ParseQualIdent(bool lhs)
{
	Declaration* dec = nullptr;

	if (mScanner->mToken == TK_COLCOLON)
	{
		mScanner->NextToken();
		if (mScanner->mToken == TK_IDENT)
		{
			DeclarationScope* scope = mScope;
			while (scope->mLevel > SLEVEL_STATIC)
				scope = scope->mParent;
			dec = scope->Lookup(mScanner->mTokenIdent);
		}
		else
		{
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
			return nullptr;
		}
	}
	else
	{
		if (mTemplateScope)
		{
			dec = mTemplateScope->Lookup(mScanner->mTokenIdent);
		}

		if (!dec)
			dec = mScope->Lookup(mScanner->mTokenIdent);
	}

	if (dec)
	{
		mScanner->NextToken();
		while (ConsumeTokenIf(TK_COLCOLON))
		{
			if (mScanner->mToken == TK_IDENT)
			{
				if (dec->mType == DT_NAMESPACE || dec->mType == DT_TYPE_STRUCT || dec->mType == DT_TYPE_ENUM)
				{
					Declaration* ndec = dec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_USING);

					if (!ndec && dec->mType == DT_TYPE_STRUCT && dec->mIdent == mScanner->mTokenIdent)
						ndec = dec->mScope->Lookup(mScanner->mTokenIdent->PreMangle("+"));

					if (ndec)
						dec = ndec;
					else
						mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown identifier", mScanner->mTokenIdent);
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a class or namespace");

			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");

			mScanner->NextToken();
		}
	}
	else
	{
		const Ident* ident = mScanner->mTokenIdent;
		Location	loc = mScanner->mLocation;
		mScanner->NextToken();
		if (lhs && ConsumeTokenIf(TK_COLON))
		{
			dec = new Declaration(loc, DT_CLABEL);
			dec->mIdent = ident;
		}
		else
			mErrors->Error(loc, EERR_OBJECT_NOT_FOUND, "Unknown identifier", ident);
	}

	return dec;
}

Expression* Parser::ParseLambdaExpression(void)
{
	Declaration* cdec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT);
	cdec->mIdent = Ident::Unique("lambda", mCompilationUnits->UniqueID());
	cdec->mQualIdent = mScope->Mangle(cdec->mIdent);
	cdec->mFlags |= DTF_DEFINED;

	cdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, cdec->mIdent);

	Declaration* olambda = mLambda;
	mLambda = cdec;

	Token	octoken = mCaptureToken;
	mCaptureToken = TK_NONE;

	Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);

	Declaration* cpdec = cdec->BuildConstPointer(mScanner->mLocation);

	Declaration* fdec = new Declaration(mScanner->mLocation, DT_CONST_FUNCTION);
	fdec->mIdent = Ident::Unique("operator()");
	fdec->mQualIdent = cdec->mScope->Mangle(fdec->mIdent);
	fdec->mCompilerOptions = mCompilerOptions;
	cdec->mScope->Insert(fdec->mIdent, fdec);

	Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT);
	pdec->mBase = cpdec;
	pdec->mSize = 2;

	Expression* einit = nullptr;
	
	bool	capture = false;

	ConsumeToken(TK_OPEN_BRACKET);
	if (!ConsumeTokenIf(TK_CLOSE_BRACKET))
	{
		capture = true;

		// Parse capture list list
		do {
			bool	reference = false;

			if (ConsumeTokenIf(TK_BINARY_AND))
			{
				if (mScanner->mToken == TK_IDENT)
					reference = true;
				else
					mCaptureToken = TK_BINARY_AND;
			}

			if (ConsumeTokenIf(TK_ASSIGN))
				mCaptureToken = TK_ASSIGN;
			else if (ConsumeTokenIf(TK_THIS))
			{
				Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT);
				mdec->mIdent = Ident::Unique("this");
				mdec->mQualIdent = cdec->mScope->Mangle(mdec->mIdent);
				if (cdec->mScope->Insert(mdec->mIdent, mdec))
					mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent);

				if (mThisPointer)
				{
					Expression* iexp = new Expression(mScanner->mLocation, EX_VARIABLE);
					iexp->mDecType = mThisPointer->mBase;
					iexp->mDecValue = mThisPointer;

					mdec->mBase = iexp->mDecType;
					mdec->mValue = iexp;
					mdec->mNext = cdec->mParams;
					cdec->mParams = mdec;
				}
				else
				{
					mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Use of this outside of method");
					mdec->mBase = TheVoidTypeDeclaration;
				}

				mdec->mOffset = cdec->mSize;
				mdec->mSize = mdec->mBase->mSize;
				cdec->mSize += mdec->mSize;
			}
			else if (mScanner->mToken == TK_IDENT)
			{
				Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT);
				mdec->mIdent = mScanner->mTokenIdent;
				mdec->mQualIdent = cdec->mScope->Mangle(mdec->mIdent);
				if (cdec->mScope->Insert(mdec->mIdent, mdec))
					mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent);

				Expression* iexp = nullptr;

				mScanner->NextToken();
				if (ConsumeTokenIf(TK_ASSIGN))
					iexp = ParseExpression(false);
				else
				{
					Declaration* mvdec = mScope->Lookup(mdec->mIdent);
					if (mvdec && (mvdec->mType == DT_VARIABLE || mvdec->mType == DT_ARGUMENT))
					{
						iexp = new Expression(mdec->mLocation, EX_VARIABLE);
						iexp->mDecType = mvdec->mBase;
						iexp->mDecValue = mvdec;
					}
					else
						mErrors->Error(mdec->mLocation, EERR_INVALID_CAPTURE, "Invalid variable capture", mdec->mIdent);
				}
				
				if (iexp)
				{
					if (reference)
						mdec->mBase = iexp->mDecType->BuildReference(mdec->mLocation);
					else
						mdec->mBase = iexp->mDecType;
					mdec->mValue = iexp;
					mdec->mNext = cdec->mParams;
					cdec->mParams = mdec;
				}

				mdec->mOffset = cdec->mSize;
				mdec->mSize = mdec->mBase->mSize;
				cdec->mSize += mdec->mSize;
			}

		} while (ConsumeTokenIf(TK_COMMA));

		ConsumeToken(TK_CLOSE_BRACKET);
	}

	Declaration* rtype = new Declaration(mScanner->mLocation, DT_TYPE_AUTO);

	if (mScanner->mToken == TK_OPEN_PARENTHESIS)
	{
		fdec->mBase = ParseFunctionDeclaration(rtype);
	}
	else
	{
		ConsumeToken(TK_OPEN_PARENTHESIS);
		fdec->mBase = TheConstVoidTypeDeclaration;
	}

	if (capture)
		PrependThisArgument(fdec->mBase, cpdec);

	fdec->mFlags |= fdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);

	fdec->mSection = mCodeSection;

	if (mCompilerOptions & COPT_NATIVE)
		fdec->mFlags |= DTF_NATIVE;

	fdec->mCompilerOptions = mCompilerOptions;
	fdec->mBase->mCompilerOptions = mCompilerOptions;

	fdec->mVarIndex = -1;


	int	li = mLocalIndex;

	DeclarationScope * oscope = mCaptureScope;
	mCaptureScope = mScope;

	while (mScope->mLevel >= SLEVEL_NAMESPACE)
		mScope = mScope->mParent;

	Declaration* tfdec = FunctionAutoParamsToTemplate(fdec);
	if (tfdec)
	{
		fdec = tfdec;
	}
	else
		fdec->mValue = ParseFunction(fdec->mBase);

	mScope = mCaptureScope;
	mLambda = olambda;
	mCaptureScope = oscope;
	mCaptureToken = octoken;

	Declaration* pmdec = cdec->mParams;
	while (pmdec)
	{
		Declaration* fcons = pmdec->mBase->mType == DT_TYPE_STRUCT && pmdec->mBase->mScope ? pmdec->mBase->mScope->Lookup(pmdec->mBase->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;

		Expression* ciexp;

		if (fcons)
		{
			Expression* vexp = new Expression(pmdec->mLocation, EX_QUALIFY);
			vexp->mLeft = new Expression(pmdec->mLocation, EX_VARIABLE);
			vexp->mLeft->mDecType = cdec;
			vexp->mLeft->mDecValue = vdec;
			vexp->mDecValue = pmdec;
			vexp->mDecType = pmdec->mBase;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = fcons;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
			fexp->mLeft = cexp;
			fexp->mRight = pmdec->mValue;

			Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
			texp->mToken = TK_BINARY_AND;
			texp->mLeft = vexp;
			texp->mDecType = pmdec->mBase->BuildPointer(mScanner->mLocation);

			Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
			lexp->mLeft = texp;
			lexp->mRight = fexp->mRight;
			fexp->mRight = lexp;

			fexp = ResolveOverloadCall(fexp);

			Expression* dexp = nullptr;
			if (pmdec->mBase->mDestructor)
			{
				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = pmdec->mBase->mDestructor;
				cexp->mDecType = cexp->mDecValue->mBase;

				dexp = new Expression(mScanner->mLocation, EX_CALL);
				dexp->mLeft = cexp;
				dexp->mRight = texp;
			}

			ciexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

			ciexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
			ciexp->mLeft->mLeft = fexp;
			ciexp->mLeft->mRight = dexp;
		}
		else
		{
			ciexp = new Expression(pmdec->mLocation, EX_INITIALIZATION);
			ciexp->mToken = TK_ASSIGN;
			ciexp->mDecType = pmdec->mValue->mDecType;
			ciexp->mRight = pmdec->mValue;
			ciexp->mLeft = new Expression(pmdec->mLocation, EX_QUALIFY);
			ciexp->mLeft->mLeft = new Expression(pmdec->mLocation, EX_VARIABLE);
			ciexp->mLeft->mLeft->mDecType = cdec;
			ciexp->mLeft->mLeft->mDecValue = vdec;
			ciexp->mLeft->mDecValue = pmdec;
			ciexp->mLeft->mDecType = pmdec->mBase;
		}

		if (einit)
		{
			Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
			lexp->mLeft = einit;
			lexp->mRight = ciexp;
			einit = lexp;
		}
		else
			einit = ciexp;

		pmdec = pmdec->mNext;
	}

	fdec->mFlags |= DTF_DEFINED | DTF_REQUEST_INLINE;
	fdec->mNumVars = mLocalIndex;

	mLocalIndex = li;

	vdec->mBase = cdec;
	vdec->mVarIndex = mLocalIndex++;
	vdec->mSize = cdec->mSize;
	vdec->mFlags |= DTF_DEFINED | DTF_CONST;
	vdec->mIdent = cdec->mIdent;

	Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
	vexp->mDecType = vdec->mBase;
	vexp->mDecValue = vdec;


	if (einit)
	{
		Expression* conex = new Expression(mScanner->mLocation, EX_CONSTRUCT);
		conex->mRight = vexp;
		conex->mDecType = vexp->mDecType;

		conex->mLeft = new Expression(mScanner->mLocation, EX_LIST);
		conex->mLeft->mLeft = einit;
		conex->mLeft->mRight = nullptr;

		return conex;
	}
	else
		return vexp;
}

Declaration* Parser::ParseTypeID(bool tid, Declaration* bdec)
{
	Declaration	*	dec = bdec ? bdec : ParseBaseTypeDeclaration(0, true);

	while (ConsumeTokenIf(TK_MUL))
		dec = dec->BuildPointer(mScanner->mLocation);
	while (ConsumeTokenIf(TK_BINARY_AND))
		dec = dec->BuildReference(mScanner->mLocation);
	if (tid && mScanner->mToken == TK_OPEN_PARENTHESIS)
		dec = ParseFunctionDeclaration(dec);
	return dec;
}

Expression* Parser::ParseCastExpression(Expression* exp)
{
	if (exp->mType == EX_TYPE)
	{
		if (mScanner->mToken == TK_OPEN_BRACE)
		{
			if (mFunctionType)
			{
				Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
				vdec->mBase = exp->mDecType;
				vdec->mVarIndex = mLocalIndex++;
				vdec->mFlags |= DTF_DEFINED;
				vdec->mSize = vdec->mBase->mSize;

				Expression* nexp = new Expression(mScanner->mLocation, EX_VARIABLE);
				nexp->mDecValue = vdec;
				nexp->mDecType = vdec->mBase;

				Expression* iexp = ParseVarInitExpression(nexp);
				if (iexp)
				{
					if (iexp->mType == EX_INITIALIZATION || iexp->mType == EX_CONSTRUCT)
						exp = iexp;
					else
					{
						Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);
						Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
						lexp->mLeft = iexp;
						lexp->mRight = nullptr;
						cexp->mLeft = lexp;
						cexp->mRight = nexp;
						cexp->mDecType = vdec->mBase;

						exp = cexp;
					}
				}
				else
					exp = nexp;
			}
			else
			{
				Declaration* cdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
				cdec->mFlags |= DTF_CONST | DTF_STATIC | DTF_GLOBAL;
				cdec->mBase = exp->mDecType;

				Expression* cexp = new Expression(mScanner->mLocation, EX_VARIABLE);
				cexp->mDecValue = cdec;


				cdec->mValue = ParseConstInitExpression(cdec->mBase);
				cdec->mSection = mDataSection;
				cdec->mSize = cdec->mBase->mSize;
				cexp->mDecType = cdec->mBase;

				exp = cexp;
			}
		}
		else
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST);
			nexp->mDecType = exp->mDecType;
			if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
			{
				nexp->mLeft = ParseListExpression(false);
				ConsumeToken(TK_CLOSE_PARENTHESIS);

				nexp->mLeft = ParseCastExpression(nexp->mLeft);
			}
			else
				nexp->mLeft = ParsePrefixExpression(false);
			nexp = CheckOperatorOverload(nexp);
			exp = nexp->ConstantFold(mErrors, mDataSection);
		}
	}

	return exp;
}

Expression* Parser::ParseIdentExpression(const Location & eloc, Declaration* dec, bool lhs, bool tid)
{
	Expression* exp = nullptr;

	if (dec->mTemplate && mScanner->mToken == TK_LESS_THAN)
	{
		dec = ParseTemplateExpansion(dec->mTemplate, nullptr);
		while (ConsumeTokenIf(TK_COLCOLON))
		{
			if (mScanner->mToken == TK_IDENT)
			{
				if (dec->mType == DT_NAMESPACE || dec->mType == DT_TYPE_STRUCT || dec->mType == DT_TYPE_ENUM)
				{
					Declaration* ndec = dec->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_USING);

					if (ndec)
						dec = ndec;
					else
						mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Unknown identifier", mScanner->mTokenIdent);
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a class or namespace");

			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");

			mScanner->NextToken();
		}
	}

	if (dec->mType == DT_CONST_INTEGER || dec->mType == DT_CONST_FLOAT || dec->mType == DT_CONST_FUNCTION || dec->mType == DT_CONST_ASSEMBLER || dec->mType == DT_LABEL || dec->mType == DT_LABEL_REF)
	{
		exp = new Expression(eloc, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;
		exp->mConst = true;
	}
	else if (dec->mType == DT_VARIABLE || dec->mType == DT_ARGUMENT)
	{
		if (/*(dec->mFlags & DTF_STATIC) &&*/ (dec->mFlags & DTF_CONST) && dec->mValue)
		{
			if (dec->mBase->IsNumericType())
			{
				if (dec->mValue->mType == EX_CONSTANT)
				{
					exp = dec->mValue;
				}
			}
			else if (dec->mBase->mType == DT_TYPE_POINTER)
			{
				if (dec->mValue->mType == EX_CONSTANT)
				{
					if (dec->mValue->mDecValue->mType == DT_CONST_ADDRESS || dec->mValue->mDecValue->mType == DT_CONST_POINTER)
						exp = dec->mValue;
				}
			}
		}

		if (!exp)
		{
			exp = new Expression(eloc, EX_VARIABLE);
			exp->mDecValue = dec;
			exp->mDecType = dec->mBase;
		}
	}
	else if (dec->mType == DT_PACK_ARGUMENT)
	{
		exp = new Expression(mScanner->mLocation, EX_PACK);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;
	}
	else if (dec->mType == DT_PACK_TYPE)
	{
		exp = new Expression(mScanner->mLocation, EX_PACK_TYPE);
		exp->mDecValue = nullptr;
		exp->mDecType = dec;
	}
	else if (dec->mType <= DT_TYPE_FUNCTION)
	{
		if (lhs)
			exp = ParseDeclarationExpression(dec);
		else
		{
			exp = new Expression(mScanner->mLocation, EX_TYPE);
			exp->mDecValue = nullptr;
			exp->mDecType = ParseTypeID(tid, dec);
		}
	}
	else if (dec->mType == DT_CONST_TEMPLATE)
	{
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = TheSignedIntTypeDeclaration;
	}
	else if (dec->mType == DT_PACK_TEMPLATE)
	{
		exp = new Expression(mScanner->mLocation, EX_PACK_TYPE);
		exp->mDecType = dec;
	}
	else if (dec->mType == DT_ELEMENT)
	{
		mErrors->Error(mScanner->mLocation, EERR_NON_STATIC_MEMBER, "Non static member access", mScanner->mTokenIdent);
	}
	else if (dec->mType == DT_CLABEL)
	{
		exp = new Expression(dec->mLocation, EX_LABEL);
		exp->mDecValue = dec;
	}
	else
	{
		mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid identifier", mScanner->mTokenIdent);
	}

	return exp;
}

Expression* Parser::ParseSimpleExpression(bool lhs, bool tid)
{
	Declaration* dec = nullptr;
	Expression* exp = nullptr, * rexp = nullptr;

	Location	eloc(mScanner->mLocation);

	switch (mScanner->mToken)
	{
	case TK_INT:
	case TK_SHORT:
	case TK_LONG:
	case TK_FLOAT:
	case TK_CHAR:
	case TK_BOOL:
	case TK_VOID:
	case TK_UNSIGNED:
	case TK_SIGNED:
	case TK_CONST:
		if (lhs)
			exp = ParseDeclarationExpression(nullptr);
		else
		{
			exp = new Expression(mScanner->mLocation, EX_TYPE);
			exp->mDecValue = nullptr;
			exp->mDecType = ParseTypeID(tid);
		}
		break;

	case TK_VOLATILE:
	case TK_STRUCT:
	case TK_CLASS:
	case TK_UNION:
	case TK_TYPEDEF:
	case TK_STATIC:
	case TK_AUTO:
	case TK_STRIPED:
	case TK_DECLTYPE:
		exp = ParseDeclarationExpression(nullptr);
		break;

	case TK_USING:
		ParseDeclaration(nullptr, true, true, false);
		break;

	case TK_CHARACTER:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mCharMap[(unsigned char)mScanner->mTokenInteger];
		dec->mBase = TheUnsignedCharTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_INTEGER:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		if (dec->mInteger < 32768)
			dec->mBase = TheSignedIntTypeDeclaration;
		else
			dec->mBase = TheUnsignedIntTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_INTEGERU:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		dec->mBase = TheUnsignedIntTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_INTEGERL:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		if (dec->mInteger < 0x80000000)
			dec->mBase = TheSignedLongTypeDeclaration;
		else
			dec->mBase = TheUnsignedLongTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_INTEGERUL:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		dec->mBase = TheUnsignedLongTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_NUMBER:
		dec = new Declaration(mScanner->mLocation, DT_CONST_FLOAT);
		dec->mBase = TheFloatTypeDeclaration;
		dec->mNumber = mScanner->mTokenNumber;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_STRING:
	{
		dec = new Declaration(mScanner->mLocation, DT_CONST_DATA);
		int	size = mScanner->mTokenStringSize;
		dec->mSize = size + 1;
		dec->mVarIndex = -1;
		dec->mSection = mCodeSection;
		dec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_ARRAY);
		dec->mBase->mSize = dec->mSize;
		dec->mBase->mBase = TheConstCharTypeDeclaration;
		dec->mBase->mFlags |= DTF_DEFINED | DTF_CONST;
		uint8* d = new uint8[size + 1];
		dec->mData = d;

		int i = 0;
		while (i < size)
		{
			d[i] = mCharMap[(uint8)mScanner->mTokenString[i]];
			i++;
		}
		d[size] = 0;

		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();

		// automatic string concatenation
		while (mScanner->mToken == TK_STRING)
		{
			int	s = mScanner->mTokenStringSize;
			uint8* d = new uint8[size + s + 1];
			memcpy(d, dec->mData, size);
			int i = 0;
			while (i < s)
			{
				d[size + i] = mCharMap[(uint8)mScanner->mTokenString[i]];
				i++;
			}
			size += s;
			d[size] = 0;
			dec->mSize = size + 1;
			delete[] dec->mData;
			dec->mData = d;
			mScanner->NextToken();
		}
		break;
	}
	case TK_TRUE:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mBase = TheBoolTypeDeclaration;
		dec->mInteger = 1;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_FALSE:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mBase = TheBoolTypeDeclaration;
		dec->mInteger = 0;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_NULL:
		dec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS);
		dec->mBase = TheNullPointerTypeDeclaration;
		dec->mInteger = 0;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_THIS:
		if (mLambda)
		{
			dec = mLambda->mScope->Lookup(Ident::Unique("this"), SLEVEL_CLASS);
			if (dec)
			{
				Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE);
				texp->mDecType = mThisPointer->mBase;
				texp->mDecValue = mThisPointer;

				Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX);
				dexp->mToken = TK_MUL;
				dexp->mDecType = texp->mDecType->mBase;
				dexp->mLeft = texp;

				dexp = dexp->ConstantFold(mErrors, mDataSection);

				exp = new Expression(mScanner->mLocation, EX_QUALIFY);
				exp->mLeft = dexp;
				exp->mDecType = dec->mBase;
				exp->mDecValue = dec;
			}
			else
				mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Use of this outside of method");
		}
		else if (mThisPointer)
		{
			exp = new Expression(mScanner->mLocation, EX_VARIABLE);
			exp->mDecType = mThisPointer->mBase;
			exp->mDecValue = mThisPointer;
		}
		else
			mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Use of this outside of method");

		mScanner->NextToken();
		break;
	case TK_COLCOLON:
		dec = ParseQualIdent(lhs);
		if (dec)
			exp = ParseIdentExpression(eloc, dec, lhs);
		break;

	case TK_IDENT:
		if (mLambda && mCaptureToken != TK_NONE && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS) && !mLambda->mScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS))
		{
			Declaration * mvdec = mCaptureScope->Lookup(mScanner->mTokenIdent, SLEVEL_CLASS);
			if (mvdec && mvdec->mType == DT_VARIABLE)
			{
				Declaration* mdec = new Declaration(mScanner->mLocation, DT_ELEMENT);
				mdec->mIdent = mScanner->mTokenIdent;
				mdec->mQualIdent = mLambda->mScope->Mangle(mdec->mIdent);
				if (mLambda->mScope->Insert(mdec->mIdent, mdec))
					mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate lambda capture", mdec->mIdent);

				Expression* iexp = new Expression(mdec->mLocation, EX_VARIABLE);
				iexp->mDecType = mvdec->mBase;
				iexp->mDecValue = mvdec;

				if (mCaptureToken == TK_BINARY_AND)
					mdec->mBase = iexp->mDecType->BuildReference(mdec->mLocation);
				else
					mdec->mBase = iexp->mDecType;
				mdec->mValue = iexp;
				mdec->mNext = mLambda->mParams;
				mLambda->mParams = mdec;

				mdec->mOffset = mLambda->mSize;
				mdec->mSize = mdec->mBase->mSize;
				mLambda->mSize += mdec->mSize;
			}
		}

		if (mThisPointer && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_FUNCTION))
		{
			int offset;
			uint64 flags;

			if (mThisPointer->mType == DT_ARGUMENT)
				dec = MemberLookup(mThisPointer->mBase->mBase, mScanner->mTokenIdent, offset, flags);
			else if (mThisPointer->mType == DT_TYPE_POINTER)
				dec = MemberLookup(mThisPointer->mBase, mScanner->mTokenIdent, offset, flags);

			if (dec)
			{
				if ((dec->mType == DT_ELEMENT || dec->mType == DT_CONST_FUNCTION) && !(dec->mFlags & DTF_STATIC))
				{
					if (mThisPointer->mType == DT_TYPE_POINTER)
					{
						mErrors->Error(mScanner->mLocation, ERRO_THIS_OUTSIDE_OF_METHOD, "Invalid non static member");
					}
					else
					{
						Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE);
						texp->mDecType = mThisPointer->mBase;
						texp->mDecValue = mThisPointer;

						Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX);
						dexp->mToken = TK_MUL;
						dexp->mDecType = texp->mDecType->mBase;
						dexp->mLeft = texp;

						dexp = dexp->ConstantFold(mErrors, mDataSection);

						exp = ParseQualify(dexp);
					}
				}
				else
					mScanner->NextToken();
			}
		}

		if (!exp)
		{
			if (!dec)
				dec = ParseQualIdent(lhs);
			if (dec)
				exp = ParseIdentExpression(eloc, dec, lhs, tid);
		}

		break;
	case TK_SIZEOF:
		mScanner->NextToken();

		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mBase = TheSignedIntTypeDeclaration;

		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		if (ConsumeTokenIf(TK_ELLIPSIS))
		{
			rexp = ParseParenthesisExpression();
			if (rexp->mType == EX_PACK)
			{
				int n = 0;
				Declaration* vdec = rexp->mDecValue->mParams;
				while (vdec)
				{
					n++;
					vdec = vdec->mNext;
				}
				dec->mInteger = n;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INVALID_PACK_USAGE, "variadic pack expected");
		}
		else
		{
			rexp = ParseParenthesisExpression();
			Declaration* btype;
			if (rexp->mDecType->IsReference())
				btype = rexp->mDecType->mBase;
			else
				btype = rexp->mDecType;

			if (btype->mFlags & DTF_DEFINED)
				dec->mInteger = btype->mSize;
			else
			{
				exp->mType = EX_PREFIX;
				exp->mToken = TK_SIZEOF;
				exp->mLeft = new Expression(mScanner->mLocation, EX_TYPE);
				exp->mLeft->mDecType = btype;
				exp->mLeft->mDecValue = nullptr;
			}
		}

		break;

	case TK_OPEN_PARENTHESIS:
		mScanner->NextToken();
		exp = ParseListExpression(true);
		ConsumeToken(TK_CLOSE_PARENTHESIS);

		if (exp->mType == EX_LIST)
			exp->mType = EX_COMMA;
		exp = ParseCastExpression(exp);
		break;
	case TK_OPEN_BRACKET:
		if (mCompilerOptions & COPT_CPLUSPLUS)
			exp = ParseLambdaExpression();
		else
		{
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Term starts with invalid token", TokenNames[mScanner->mToken]);
			mScanner->NextToken();
		}
		break;
	case TK_OPEN_BRACE:
		if (!lhs)
		{
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_AGGREGATE);
			exp->mLeft = ParseListExpression(false);
			exp->mDecType = TheConstVoidTypeDeclaration;
			ConsumeToken(TK_CLOSE_BRACE);
		}
		else
		{
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Term starts with invalid token", TokenNames[mScanner->mToken]);
			mScanner->NextToken();
		}
		break;
	case TK_ASM:
	{

		mScanner->NextToken();

		uint64	aflags = ParseAssemblerFlags();

		if (mScanner->mToken == TK_OPEN_BRACE)
		{
			mScanner->NextToken();
			exp = ParseAssembler();
			exp->mDecValue->mFlags |= aflags;

			exp->mDecType = TheSignedLongTypeDeclaration;
			if (mScanner->mToken == TK_CLOSE_BRACE)
				mScanner->NextToken();
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");
		}
		else
		{
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");
			exp = new Expression(mScanner->mLocation, EX_VOID);
		}
	}	break;
	default:
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Term starts with invalid token", TokenNames[mScanner->mToken]);
		mScanner->NextToken();
	}

	if (!exp)
	{
		exp = new Expression(mScanner->mLocation, EX_VOID);
		exp->mDecType = TheVoidTypeDeclaration;
	}

	return exp;
}

Declaration* Parser::MemberLookup(Declaration* dtype, const Ident* ident, int & offset, uint64& flags)
{
	if ((mCompilerOptions & COPT_CPLUSPLUS) && ident == dtype->mIdent)
		return nullptr;

	Declaration* mdec = dtype->mScope->Lookup(ident, SLEVEL_CLASS);
	offset = 0;
	flags = 0;

	if (!mdec)
	{
		Declaration* bcdec = dtype->mBase;

		while (bcdec)
		{
			int		noffset;
			uint64	nflags;

			Declaration* ndec = MemberLookup(bcdec->mBase, ident, noffset, nflags);
			if (ndec)
			{
				if (mdec)
					mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Multiple definitions for member", ident);
				else
				{
					mdec = ndec;
					offset = noffset + bcdec->mOffset;
					flags = nflags | bcdec->mFlags;
				}
			}
			bcdec = bcdec->mNext;
		}
	}
	else
		flags = mdec->mFlags;

	return mdec;
}

uint64 Parser::ParseAssemblerFlags(void)
{
	uint64	flags = 0;

	if (ConsumeTokenIf(TK_VOLATILE))
		flags |= DTF_VOLATILE;

	if (ConsumeTokenIf(TK_PRESERVES))
	{
		ConsumeToken(TK_OPEN_PARENTHESIS);
		if (mScanner->mToken == TK_IDENT)
		{
			char* cp = mScanner->mTokenIdent->mString;
			while (*cp)
			{
				switch (*cp)
				{
				case 'a':
				case 'A':
					flags |= DTF_ASM_PRESERVE_A;
					break;
				case 'x':
				case 'X':
					flags |= DTF_ASM_PRESERVE_X;
					break;
				case 'y':
				case 'Y':
					flags |= DTF_ASM_PRESERVE_Y;
					break;
				default:
					mErrors->Error(mScanner->mLocation, EERR_ASM_INVALID_REGISTER, "Invalid register specified", mScanner->mTokenIdent);
				}
				cp++;
			}
			mScanner->NextToken();
		}
		ConsumeToken(TK_CLOSE_PARENTHESIS);
	}

	return flags;
}

Expression* Parser::ParseQualify(Expression* exp)
{
	Declaration* dtype = exp->mDecType;

	exp = exp->ConstantFold(mErrors, mDataSection);

	if (dtype->IsReference())
		dtype = dtype->mBase;

	if (dtype->mType == DT_TYPE_STRUCT || dtype->mType == DT_TYPE_UNION)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_QUALIFY);
		nexp->mLeft = exp;

		int moffset = 0;
		uint64	mflags = 0;
		Declaration* mdec = nullptr;
		const Ident* ident = nullptr;
		bool	destructor = false;

		if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_BINARY_NOT)
		{
			mScanner->NextToken();
			if (mScanner->mToken == TK_IDENT)
			{
				ident = mScanner->mTokenIdent;
				if (mTemplateScope)
				{
					Declaration* dec = mTemplateScope->Lookup(ident);
					if (dec)
						ident = dec->mIdent;
				}

				ident = ident->PreMangle("~");
				destructor = true;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
		}
		else if (mScanner->mToken == TK_IDENT)
			ident = mScanner->mTokenIdent;

		if (ident)
		{
			mdec = MemberLookup(dtype, ident, moffset, mflags);

			if (mdec)
			{
				if (mflags & DTF_PROTECTED)
				{
					Declaration* tp = mThisPointer;
					if (tp && tp->mType == DT_ARGUMENT)
						tp = tp->mBase;
					if (!(tp && tp->mBase->IsConstSame(dtype)))
					{
						if (dtype->mFriends.Contains(mFunction))
							;
						else if (mThisPointer && mThisPointer->mBase && mThisPointer->mBase->mBase && dtype->mFriends.Contains(mThisPointer->mBase->mBase->ToMutableType()))
							;
						else
							mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not visible", ident);
					}
				}

				mScanner->NextToken();
				if (mdec->mType == DT_ELEMENT)
				{
					nexp->mDecValue = mdec;
					nexp->mDecType = mdec->mBase;
					if (exp->mDecType->mFlags & DTF_CONST)
						nexp->mDecType = nexp->mDecType->ToConstType();

					exp = nexp->ConstantFold(mErrors, mDataSection);
				}
				else if (mdec->mType == DT_VARIABLE)
				{
					nexp = new Expression(mScanner->mLocation, EX_VARIABLE);
					nexp->mDecValue = mdec;
					nexp->mDecType = mdec->mBase;
					exp = nexp->ConstantFold(mErrors, mDataSection);
				}
				else if (mdec->mType == DT_CONST_FUNCTION)
				{
					if (mdec->mTemplate && mScanner->mToken == TK_LESS_THAN)
						mdec = ParseTemplateExpansion(mdec->mTemplate, nullptr);

					if (mdec->mBase->mFlags & DTF_FUNC_THIS)
					{
						ConsumeToken(TK_OPEN_PARENTHESIS);

						nexp = new Expression(mScanner->mLocation, EX_CALL);
						if (mInlineCall)
							nexp->mType = EX_INLINE;
						mInlineCall = false;

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						if (ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
							nexp->mRight = nullptr;
						else
						{
							nexp->mRight = ParseListExpression(false, mdec->mBase->mParams->mNext);
							ConsumeToken(TK_CLOSE_PARENTHESIS);
						}

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						if (exp->mDecType->IsReference())
							texp->mDecType->mBase = exp->mDecType->mBase;
						else
							texp->mDecType->mBase = exp->mDecType;
						texp->mDecType->mSize = 2;

						if (nexp->mRight)
						{
							Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
							lexp->mLeft = texp;
							lexp->mRight = nexp->mRight;
							nexp->mRight = lexp;
						}
						else
							nexp->mRight = texp;

						nexp = ResolveOverloadCall(nexp);

						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						if (nexp->mLeft->mDecType->mFlags & DTF_VIRTUAL)
							nexp->mType = EX_VCALL;

						exp = nexp;
					}
					else
					{
						nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mDecValue = mdec;
						nexp->mDecType = mdec->mBase;
						exp = nexp;
					}
				}
				else if (mdec->mType == DT_CONST_INTEGER || mdec->mType == DT_CONST_FLOAT || mdec->mType == DT_CONST_POINTER || mdec->mType == DT_CONST_ADDRESS)
				{
					nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp->mDecValue = mdec;
					nexp->mDecType = mdec->mBase;
					exp = nexp;
				}
			}
			else if (destructor)
			{
				mScanner->NextToken();
				ConsumeToken(TK_OPEN_PARENTHESIS);
				ConsumeToken(TK_CLOSE_PARENTHESIS);
			}
			else
			{
				mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not found", mScanner->mTokenIdent);
				mScanner->NextToken();
			}
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Struct member identifier expected");

	}
	else if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_BINARY_NOT)
	{
		mScanner->NextToken();
		if (mScanner->mToken == TK_IDENT)
		{
			const Ident	*	ident = mScanner->mTokenIdent;
			if (mTemplateScope)
			{
				Declaration* dec = mTemplateScope->Lookup(ident);
				if (dec == dtype)
				{
					mScanner->NextToken();
					ConsumeToken(TK_OPEN_PARENTHESIS);
					ConsumeToken(TK_CLOSE_PARENTHESIS);

					exp = new Expression(mScanner->mLocation, EX_VOID);
					exp->mDecType = TheConstVoidTypeDeclaration;
				}
			}
			else if (ident == dtype->mIdent)
			{
				mScanner->NextToken();
				ConsumeToken(TK_OPEN_PARENTHESIS);
				ConsumeToken(TK_CLOSE_PARENTHESIS);

				exp = new Expression(mScanner->mLocation, EX_VOID);
				exp->mDecType = TheConstVoidTypeDeclaration;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Destructor identifier expected");
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
	}
	else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_ASSEMBLER)
	{
		if (mScanner->mToken == TK_IDENT)
		{
			Declaration* ldec = exp->mDecValue->mBase->mScope->Lookup(mScanner->mTokenIdent);
			if (ldec)
			{
				exp->mDecValue = ldec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Assembler label not found", mScanner->mTokenIdent);
			mScanner->NextToken();
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
	}
	else
		mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Struct expected");

	return exp;
}

static const int NOOVERLOAD = 0x7fffffff;

int Parser::OverloadDistance(Declaration* fdec, Expression* pexp)
{
	if (fdec->mTemplate)
	{
		// this is a constructor, so avoid instantiating a single parameter with the type itself
		// as this would only lead to misery and pain and a crashing recursion
		if (fdec->mIdent->mString[0] == '+')
		{
			if (fdec->mBase->mParams && fdec->mBase->mParams->mNext && !fdec->mBase->mParams->mNext->mNext && 
				fdec->mBase->mParams->mNext->mBase->mType == DT_TYPE_TEMPLATE &&
				fdec->mBase->mParams->mBase->mBase)
			{
				if (pexp->mRight && pexp->mRight->mDecType->IsConstSame(fdec->mBase->mParams->mBase->mBase))
					return NOOVERLOAD;
			}
		}

		Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
		tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);
		if (!tdec->CanResolveTemplate(pexp, fdec))
			return NOOVERLOAD;
	}

	Declaration* pdec = fdec->mBase->mParams;

	int dist = 0;

	bool	packtemp = false;
	while (pexp)
	{
		Expression* ex = pexp;
		if (pexp->mType == EX_LIST)
		{
			ex = pexp->mLeft;
			pexp = pexp->mRight;
		}
		else
			pexp = nullptr;

		if (pdec)
		{
			Declaration* ptype = pdec->mBase;
			Declaration* etype = ex->mDecType;
			if (etype->mType == DT_TYPE_REFERENCE)
				etype = etype->mBase;

			if (ptype->mType == DT_PACK_TEMPLATE || ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_PACK_TEMPLATE)
				packtemp = true;

			if (ptype->mType == DT_TYPE_TEMPLATE || ptype->mType == DT_PACK_TEMPLATE)
			{
				dist += 1;
			}			
			else if (ptype->mType == DT_TYPE_REFERENCE && (ptype->mBase->mType == DT_TYPE_TEMPLATE || ptype->mBase->mType == DT_PACK_TEMPLATE))
			{
				if (ex->IsLValue())
					dist += 1;
				else if (ptype->mBase->mFlags & DTF_CONST)
					dist += 1;
				else
					return NOOVERLOAD;
			}
			else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_INTEGER)
			{
				if (ptype->mSize == etype->mSize)
				{
					if ((ptype->mFlags & DTF_SIGNED) == (etype->mFlags & DTF_SIGNED))
						dist += 0;
					else
						dist += 8;
				}
				else if (ptype->mSize > etype->mSize)
				{
					if (ptype->mFlags & DTF_SIGNED)
					{
						dist += 2;
					}
					else if (etype->mFlags & DTF_SIGNED)
					{
						dist += 8;
					}
					else
						dist += 2;
				}
				else if (ex->mType == EX_CONSTANT && ex->mDecValue->mType == DT_CONST_INTEGER)
				{
					int64 v = ex->mDecValue->mInteger;

					if (ptype->mFlags & DTF_SIGNED)
					{
						if (v >= -128 && v <= 127)
							dist += 2;
						else if (ptype->mSize >= 2 && v >= -32768 && v <= 32767)
							dist += 2;
						else if (ptype->mSize == 4)
							dist += 2;
						else
							dist += 32;
					}
					else if (v >= 0)
					{
						if (v <= 255)
							dist += 2;
						else if (ptype->mSize >= 2 && v <= 65535)
							dist += 2;
						else if (ptype->mSize == 4)
							dist += 2;
						else
							dist += 32;
					}
					else
						dist += 32;
				}
				else
					dist += 32;
			}
			else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_FLOAT)
				dist += 0;
			else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_FLOAT)
				dist += 16;
			else if (ptype->mType == DT_TYPE_INTEGER && etype->mType == DT_TYPE_ENUM)
				dist += 32;
			else if (ptype->mType == DT_TYPE_FLOAT && etype->mType == DT_TYPE_INTEGER)
				dist += 8;
			else if (ptype->IsSame(ex->mDecType))
				;
			else if (CanCoerceExpression(ex, ptype))
			{
				dist += 512;
				if (ptype->mType == DT_TYPE_REFERENCE)
					dist += 8;
				else if (ptype->mType == DT_TYPE_RVALUEREF)
					dist += 4;
			}
			else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT)
			{
				if (ex->IsLValue())
					dist += 4;
				else if (ptype->mBase->mFlags & DTF_CONST)
					dist += 8;
				else
					return NOOVERLOAD;

				if (ptype->mBase->mTemplate)
				{
					dist += 16;
				}
				else
				{
					int	ncast = 0;
					Declaration* ext = ex->mDecType;
					while (ext && !ext->IsConstSame(ptype->mBase))
					{
						ncast++;
						ext = ext->mBase;
					}

					if (ext)
					{
						if ((etype->mFlags & DTF_CONST) && !(ptype->mBase->mFlags & DTF_CONST))
							return NOOVERLOAD;

						dist += 32 * ncast;
					}
					else
						return NOOVERLOAD;
				}
			}
			else if (ptype->mType == DT_TYPE_POINTER && etype->mType == DT_TYPE_POINTER && ptype->mBase->IsSame(etype->mBase))
				;
			else if (ptype->mType == DT_TYPE_POINTER && (etype->mType == DT_TYPE_ARRAY || etype->mType == DT_TYPE_POINTER) && ptype->mBase->IsSameMutable(etype->mBase))
				dist += 2;
			else if (ptype->mType == DT_TYPE_POINTER && etype->mType == DT_TYPE_FUNCTION && ptype->mBase->IsSame(etype))
				dist += 0;
			else if (ptype->mType == DT_TYPE_POINTER && etype->mType == DT_TYPE_POINTER && etype->mBase->mType == DT_TYPE_VOID)
				dist += 0;
			else if (ptype->IsSubType(etype))
				dist += 256;
			else if (ptype->mType == DT_TYPE_RVALUEREF && ptype->mBase->IsSameMutable(etype) && ex->IsRValue())
			{
				dist += 2;
			}
			else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->IsSameMutable(etype))
			{
				if (ex->IsLValue())
					dist += 4;
				else if (ptype->mBase->mFlags & DTF_CONST)
					dist += 8;
				else
					return NOOVERLOAD;
			}
			else if (ptype->mType == DT_TYPE_REFERENCE && (ptype->mBase->mFlags & DTF_CONST) && ptype->mBase->CanAssign(etype))
			{
				dist += 32;
			}
			else if (ptype->IsSimpleType() && etype->IsSimpleType() && ptype->IsConstSame(etype))
				dist += 2;
			else if (ptype->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT)
			{
				int	ncast = 0;
				Declaration* ext = ex->mDecType;
				while (ext && !ext->IsConstSame(ptype))
				{
					ncast++;
					ext = ext->mBase;
				}

				if (ext)
					dist += 32 * ncast;
				else
					return NOOVERLOAD;
			}
			else
				return NOOVERLOAD;

			if (!packtemp)
				pdec = pdec->mNext;
		}
		else if (fdec->mBase->mFlags & DTF_VARIADIC)
		{
			dist += 1024;
			break;
		}
		else
			return NOOVERLOAD;
	}

	while (pdec && pdec->mValue)
	{
		dist += 1024;
		pdec = pdec->mNext;
	}

	if (pdec)
	{
		Declaration* ptype = pdec->mBase;
		if (ptype->mType == DT_PACK_TEMPLATE || ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_PACK_TEMPLATE)
			packtemp = true;
	}

	if (pdec && packtemp)
		return dist;

	if (pdec)
		return NOOVERLOAD;

	return dist;
}

bool Parser::CanCoerceExpression(Expression* exp, Declaration* type)
{
	Declaration* tdec = exp->mDecType;
	while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
		tdec = tdec->mBase;
	while (type->mType == DT_TYPE_REFERENCE || type->mType == DT_TYPE_RVALUEREF)
		type = type->mBase;

	if (tdec->mType == DT_TYPE_STRUCT)
	{
		Declaration* fexp = tdec->mScope->Lookup(Ident::Unique("(cast)"));
		if (fexp)
		{
			while (fexp && !fexp->mBase->mBase->IsSame(type))
				fexp = fexp->mNext;
			if (fexp)
				return true;
		}
	}

	if (type->mType == DT_TYPE_STRUCT)
	{
		if (!type->IsConstSame(tdec))
		{
			Declaration* fcons = type->mScope ? type->mScope->Lookup(type->mIdent->PreMangle("+")) : nullptr;
			if (fcons)
			{
				while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && 
								  (fcons->mBase->mParams->mNext->mBase->mType == DT_TYPE_TEMPLATE || fcons->mBase->mParams->mNext->mBase->CanAssign(tdec))))
					fcons = fcons->mNext;

				if (fcons)
					return true;
			}
		}
	}

	return false;
}

Expression* Parser::CoerceExpression(Expression* exp, Declaration* type)
{
	Declaration* tdec = exp->mDecType;

	while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
		tdec = tdec->mBase;

	if (type->mType == DT_TYPE_REFERENCE && type->mBase->mType == DT_TYPE_STRUCT && tdec->mType == DT_TYPE_STRUCT && type->mBase->IsSubType(tdec))
		return exp;

	while (type->mType == DT_TYPE_REFERENCE || type->mType == DT_TYPE_RVALUEREF)
		type = type->mBase;

	if (type->mType == DT_TYPE_POINTER && tdec->mType == DT_TYPE_INTEGER && exp->mType == EX_CONSTANT && exp->mDecValue->mInteger == 0)
	{
		if (mCompilerOptions & COPT_CPLUSPLUS)
			mErrors->Error(exp->mLocation, EWARN_NUMERIC_0_USED_AS_NULLPTR, "Numeric 0 used for nullptr");
		Expression* nexp = new Expression(exp->mLocation, EX_CONSTANT);
		nexp->mDecType = TheNullPointerTypeDeclaration;
		nexp->mDecValue = TheNullptrConstDeclaration;
		return nexp;
	}
	else if (type->mType == DT_TYPE_INTEGER && tdec->mType == DT_TYPE_INTEGER && exp->mType == EX_CONSTANT && (type->mSize != tdec->mSize || (type->mFlags & DTF_SIGNED) != (tdec->mFlags & DTF_SIGNED)))
	{
		int64	sval = 1ULL << (8 * type->mSize);
		int64	v = exp->mDecValue->mInteger;
		
		if (type->mFlags & DTF_SIGNED)
		{
			if (v < - (sval >> 1) || v >= (sval >> 1))
				mErrors->Error(exp->mLocation, EWARN_CONSTANT_TRUNCATED, "Integer constant truncated");
			v &= (sval - 1);
			if (v & (sval >> 1))
				v -= sval;
		}
		else
		{
			if (v < 0 || v >= sval)
				mErrors->Error(exp->mLocation, EWARN_CONSTANT_TRUNCATED, "Integer constant truncated");
			v &= (sval - 1);
		}

		Expression* ex = new Expression(exp->mLocation, EX_CONSTANT);
		Declaration* dec = new Declaration(exp->mLocation, DT_CONST_INTEGER);
		dec->mBase = type;
		dec->mInteger = v;
		ex->mDecValue = dec;
		ex->mDecType = type;
		return ex;
	}

	if (tdec->mType == DT_TYPE_STRUCT)
	{
		Declaration* fexp = tdec->mScope->Lookup(Ident::Unique("(cast)"));
		if (fexp)
		{
			while (fexp && !fexp->mBase->mBase->IsSame(type))
				fexp = fexp->mNext;
			if (!fexp && type->mType == DT_TYPE_INTEGER)
			{
				fexp = tdec->mScope->Lookup(Ident::Unique("(cast)"));
				while (fexp && !fexp->mBase->mBase->IsSame(TheSignedIntTypeDeclaration))
					fexp = fexp->mNext;
			}

			if (fexp)
			{
				Expression* aexp = new Expression(exp->mLocation, EX_PREFIX);
				aexp->mToken = TK_BINARY_AND;
				aexp->mDecType = tdec->BuildPointer(exp->mLocation);
				aexp->mLeft = exp;

				Expression* nexp = new Expression(exp->mLocation, EX_CALL);
				nexp->mLeft = new Expression(exp->mLocation, EX_CONSTANT);
				nexp->mLeft->mDecType = fexp->mBase;
				nexp->mLeft->mDecValue = fexp;
				nexp->mRight = aexp;
				nexp->mDecType = fexp->mBase->mBase;

				return nexp;
			}
		}

		if (type->mType == DT_TYPE_POINTER && type->mBase->mType == DT_TYPE_FUNCTION)
		{
			Declaration* fr = tdec->mScope->Lookup(Ident::Unique("operator()"));
			if (fr && !(fr->mBase->mFlags & DTF_FUNC_THIS))
			{
				Expression* nexp = new Expression(exp->mLocation, EX_CONSTANT);
				nexp->mDecType = fr->mBase;
				nexp->mDecValue = fr;

				return nexp;
			}
		}
	}

	if (type->mType == DT_TYPE_STRUCT)
	{
		if (!type->IsConstSame(tdec))
		{
			Declaration* fcons = type->mScope ? type->mScope->Lookup(type->mIdent->PreMangle("+")) : nullptr;
			if (fcons)
			{
#if 0
				while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && fcons->mBase->mParams->mNext->mBase->CanAssign(tdec)))
					fcons = fcons->mNext;

				if (fcons)
#endif
				{
					Declaration* vdec = AllocTempVar(type->ToMutableType());
#if 0
					Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);

					vdec->mBase = type->ToMutableType();
					vdec->mVarIndex = mLocalIndex++;
					vdec->mSize = type->mSize;
					vdec->mFlags |= DTF_DEFINED;
#endif

					Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
					vexp->mDecType = vdec->mBase;
					vexp->mDecValue = vdec;

					Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					cexp->mDecValue = fcons;
					cexp->mDecType = cexp->mDecValue->mBase;

					Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
					fexp->mLeft = cexp;
					fexp->mRight = exp;

					Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
					texp->mToken = TK_BINARY_AND;
					texp->mLeft = vexp;
					texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
					texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
					texp->mDecType->mBase = vdec->mBase;
					texp->mDecType->mSize = 2;

					Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
					lexp->mLeft = texp;
					lexp->mRight = fexp->mRight;
					fexp->mRight = lexp;

					fexp = ResolveOverloadCall(fexp);

					Expression* dexp = nullptr;
					if (type->mDestructor)
					{
						Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
						cexp->mDecValue = type->mDestructor;
						cexp->mDecType = cexp->mDecValue->mBase;

						dexp = new Expression(mScanner->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = texp;
					}

					Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

					nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
					nexp->mLeft->mLeft = fexp;
					nexp->mLeft->mRight = dexp;

					nexp->mRight = vexp;
					nexp->mDecType = vexp->mDecType;

					return nexp;
				}
			}
		}
	}
	
#if 1
	if (type->mType == DT_TYPE_BOOL && tdec->mType == DT_TYPE_INTEGER)
	{
		Expression* ex;
		if (exp->mType == EX_CONSTANT)
		{
			ex = new Expression(exp->mLocation, EX_CONSTANT);
			if (exp->mDecValue->mInteger)
				ex->mDecValue = TheTrueConstDeclaration;
			else
				ex->mDecValue = TheFalseConstDeclaration;
		}
		else
		{
			ex = new Expression(exp->mLocation, EX_RELATIONAL);
			ex->mToken = TK_NOT_EQUAL;
			ex->mLeft = exp;
			ex->mRight = new Expression(exp->mLocation, EX_CONSTANT);
			ex->mRight->mDecType = TheSignedIntTypeDeclaration;
			ex->mRight->mDecValue =	TheZeroIntegerConstDeclaration;
		}
		ex->mDecType = type;
		return ex;
	}
#endif

	return exp;
}

void Parser::ExpandFunctionCallTemplate(Expression* exp)
{
	if (exp->mLeft->mDecValue->mTemplate)
	{
		Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
		tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);
		if (tdec->ResolveTemplate(exp->mRight, exp->mLeft->mDecValue))
		{
			exp->mLeft->mDecValue = ParseTemplateExpansion(exp->mLeft->mDecValue->mTemplate, tdec);
			exp->mLeft->mDecType = exp->mLeft->mDecValue->mBase;
		}
	}
}

void Parser::CompleteFunctionDefaultParams(Expression* exp)
{
	Declaration* fdec = exp->mLeft->mDecValue;
	Expression* lexp = exp;

	Declaration* pdec = fdec->mBase->mParams;
	Expression* pexp = lexp->mRight;
	while (pdec)
	{
		if (pexp)
		{
			Expression* exp = pexp;

			if (pexp->mType == EX_LIST)
			{
				pexp->mLeft = CoerceExpression(pexp->mLeft, pdec->mBase);
				lexp = pexp;
				pexp = pexp->mRight;
			}
			else
			{
				lexp->mRight = CoerceExpression(lexp->mRight, pdec->mBase);
				pexp = nullptr;
			}
		}
		else if (pdec->mValue)
		{
			if (lexp->mRight)
			{
				Expression* nexp = new Expression(exp->mLocation, EX_LIST);
				nexp->mLeft = lexp->mRight;
				nexp->mRight = pdec->mValue;
				lexp->mRight = nexp;
				lexp = nexp;
			}
			else
				lexp->mRight = pdec->mValue;
		}

		pdec = pdec->mNext;
	}
}

Expression * Parser::ResolveOverloadCall(Expression* exp, Expression* exp2)
{
	if (exp->mType == EX_CALL && exp->mLeft->mDecValue)
	{
		if (exp->mRight && FindPackExpression(exp->mRight))
			return exp;

		Declaration* fdec = exp->mLeft->mDecValue;
		Declaration* fdec2 = exp2 ? exp2->mLeft->mDecValue : nullptr;

		if (fdec->mType == DT_CONST_FUNCTION && fdec->mNext || fdec2)
		{
			Declaration* dbest = nullptr;
			Expression* pbest = nullptr;
			int				ibest = NOOVERLOAD, nbest = 0;

			while (fdec)
			{
				int d = OverloadDistance(fdec, exp->mRight);
				if (d == NOOVERLOAD)
					;
				else if (d < ibest)
				{
					dbest = fdec;
					pbest = exp->mRight;
					ibest = d;
					nbest = 1;
				}
				else if (d == ibest)
					nbest++;
				fdec = fdec->mNext;
			}

			while (fdec2)
			{
				int d = OverloadDistance(fdec2, exp2->mRight);
				if (d == NOOVERLOAD)
					;
				else if (d < ibest)
				{
					dbest = fdec2;
					pbest = exp2->mRight;
					ibest = d;
					nbest = 1;
				}
				else if (d == ibest)
					nbest++;
				fdec2 = fdec2->mNext;
			}

			if (ibest == NOOVERLOAD)
			{
#if _DEBUG
				fdec = exp->mLeft->mDecValue;
				while (fdec)
				{
					int d = OverloadDistance(fdec, exp->mRight);
					fdec = fdec->mNext;
				}
#endif
				mErrors->Error(FullLocation(exp->mLocation), ERRO_NO_MATCHING_FUNCTION_CALL, "No matching function call", exp->mLeft->mDecValue->mQualIdent);
			}
			else if (nbest > 1)
			{
#if _DEBUG
				fdec = exp->mLeft->mDecValue;
				while (fdec)
				{
					int d = OverloadDistance(fdec, exp->mRight);
					fdec = fdec->mNext;
				}
#endif
				mErrors->Error(FullLocation(exp->mLocation), ERRO_AMBIGUOUS_FUNCTION_CALL, "Ambiguous function call", exp->mLeft->mDecValue->mQualIdent);
			}
			else
			{
				assert(dbest);

				exp->mLeft->mDecValue = dbest;
				exp->mLeft->mDecType = dbest->mBase;
				exp->mDecType = dbest->mBase->mBase;
				exp->mRight = pbest;
			}
		}

		ExpandFunctionCallTemplate(exp);
		CompleteFunctionDefaultParams(exp);
	}

	return exp;
}

Expression* Parser::ParseConstruction(Declaration* type)
{
	Token	otk = mScanner->mToken == TK_OPEN_PARENTHESIS ? TK_CLOSE_PARENTHESIS : TK_CLOSE_BRACE;

	Expression* pexp = nullptr;
	Expression* exp = nullptr;

	Declaration* fcons = type->mScope ? type->mScope->Lookup(type->mIdent->PreMangle("+")) : nullptr;

	mScanner->NextToken();
	if (mScanner->mToken != otk)
	{
		pexp = ParseListExpression(false, fcons ? fcons->mBase->mParams->mNext : nullptr);
		ConsumeToken(otk);
	}
	else
		mScanner->NextToken();

	if (pexp && pexp->mType != EX_LIST && pexp->mDecType->IsSame(type) && !type->mCopyConstructor)
	{
		// Simple copy
		exp = pexp;
	}
	else
	{
		if (fcons)
		{
			Declaration* tdec = new Declaration(mScanner->mLocation, DT_VARIABLE);

			tdec->mBase = type;
			tdec->mVarIndex = mLocalIndex++;
			tdec->mSize = type->mSize;
			tdec->mFlags |= DTF_DEFINED | DTF_TEMPORARY;

			Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			vexp->mDecType = type;
			vexp->mDecValue = tdec;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = fcons;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
			fexp->mLeft = cexp;

			fexp->mRight = pexp;

			Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
			texp->mToken = TK_BINARY_AND;
			texp->mLeft = vexp;
			texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
			texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
			texp->mDecType->mBase = type;
			texp->mDecType->mSize = 2;

			if (fexp->mRight)
			{
				Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
				lexp->mLeft = texp;
				lexp->mRight = fexp->mRight;
				fexp->mRight = lexp;
			}
			else
				fexp->mRight = texp;

			fexp = ResolveOverloadCall(fexp);

			Expression* dexp = nullptr;
			if (type->mDestructor)
			{
				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = type->mDestructor;
				cexp->mDecType = cexp->mDecValue->mBase;

				dexp = new Expression(mScanner->mLocation, EX_CALL);
				dexp->mLeft = cexp;
				dexp->mRight = texp;
			}

			Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

			nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
			nexp->mLeft->mLeft = fexp;
			nexp->mLeft->mRight = dexp;

			nexp->mRight = vexp;
			nexp->mDecType = vexp->mDecType;

			exp = nexp;
		}
		else if (pexp)
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST);
			nexp->mDecType = type;
			nexp->mLeft = pexp;
			nexp = CheckOperatorOverload(nexp);
			exp = nexp->ConstantFold(mErrors, mDataSection);
		}
		else if (type->IsSimpleType())
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT);

			if (type->IsIntegerType())
			{
				nexp->mDecType = type;
				nexp->mDecValue = TheZeroIntegerConstDeclaration;
			}
			else if (type->mType == DT_TYPE_FLOAT)
			{
				nexp->mDecType = TheFloatTypeDeclaration;
				nexp->mDecValue = TheZeroFloatConstDeclaration;
			}
			else // Pointer
			{
				nexp->mDecType = TheNullPointerTypeDeclaration;
				nexp->mDecValue = TheNullptrConstDeclaration;
			}

			exp = nexp;
		}
		else
		{
			Declaration* tdec = new Declaration(mScanner->mLocation, DT_VARIABLE);

			tdec->mBase = type;
			tdec->mVarIndex = mLocalIndex++;
			tdec->mSize = type->mSize;
			tdec->mFlags |= DTF_DEFINED | DTF_TEMPORARY;

			Expression* nexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			nexp->mDecType = type;
			nexp->mDecValue = tdec;

			exp = nexp;
		}
	}

	return exp;
}

Expression* Parser::ParsePostfixExpression(bool lhs)
{
	Expression* exp = ParseSimpleExpression(lhs);

	for (;;)
	{
		if (ConsumeTokenIf(TK_COLCOLON))
		{

		}
		else if (ConsumeTokenIf(TK_OPEN_BRACKET))
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_INDEX);
			nexp->mLeft = exp;
			nexp->mRight = ParseExpression(false);
			ConsumeToken(TK_CLOSE_BRACKET);

			if (exp->mDecType->ValueType() == DT_TYPE_STRUCT)
			{
				nexp = CheckOperatorOverload(nexp);
				if (nexp->mType == EX_INDEX)
					mErrors->Error(mScanner->mLocation, EERR_INVALID_INDEX, "No indexing operator found");
			}
			else if (exp->mDecType->mType == DT_TYPE_ARRAY || exp->mDecType->mType == DT_TYPE_POINTER)
			{
				if (!nexp->mRight->mDecType->IsIntegerType())
					nexp->mRight = CoerceExpression(nexp->mRight, TheSignedIntTypeDeclaration);
				
				nexp->mDecType = exp->mDecType->mBase;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INVALID_INDEX, "Array expected for indexing");

			if (!nexp->mDecType)
				nexp->mDecType = TheVoidTypeDeclaration;
			exp = nexp->ConstantFold(mErrors, mDataSection, mCompilationUnits->mLinker);
		}
		else if (mScanner->mToken == TK_OPEN_BRACE && exp->mType == EX_TYPE)
		{
			if (exp->mDecType->HasConstructor())
				exp = ParseConstruction(exp->mDecType);
			else
				exp = ParseCastExpression(exp);
		}
		else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
		{
			// Explicit constructor invocation
			if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION && exp->mDecValue->mIdent && exp->mDecValue->mIdent->mString[0] == '+')
			{
				exp->mType = EX_TYPE;
				exp->mDecType = exp->mDecType->mParams->mBase->mBase;
				exp->mDecValue = nullptr;
			}

			if (exp->mType == EX_TYPE)
			{
				if (exp->mDecType->mTemplate)
				{
					mErrors->Error(mScanner->mLocation, EERR_TEMPLATE_PARAMS, "Missing template parameters", exp->mDecType->mQualIdent);
					exp->mDecType = TheConstVoidTypeDeclaration;
				}

				exp = ParseConstruction(exp->mDecType);
			}
			else
			{
				Expression* thisExp = nullptr;

				if (exp->mDecType->mType == DT_TYPE_POINTER && exp->mDecType->mBase->mType == DT_TYPE_FUNCTION)
				{
				}
				else if (exp->mDecType->mType == DT_TYPE_FUNCTION)
				{
				}
				else
				{
					Declaration* tdec = exp->mDecType;
					while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
						tdec = tdec->mBase;

					if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope)
					{
						const Ident* opident = Ident::Unique("operator()");

						Declaration* mdec = tdec->mScope->Lookup(opident);
						if (mdec)
						{
							thisExp = new Expression(exp->mLocation, EX_PREFIX);
							thisExp->mToken = TK_BINARY_AND;
							thisExp->mLeft = exp;
							thisExp->mDecType = tdec->BuildPointer(exp->mLocation);

							exp = new Expression(exp->mLocation, EX_CONSTANT);
							exp->mDecValue = mdec;
							exp->mDecType = mdec->mBase;
						}
						else
						{
							mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Function expected for call");
							exp->mDecType = TheVoidFunctionTypeDeclaration;
						}
					}
					else
					{
						mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Function expected for call");
						exp->mDecType = TheVoidFunctionTypeDeclaration;
					}

				}

				mScanner->NextToken();
				Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);
				if (mInlineCall)
					nexp->mType = EX_INLINE;
				mInlineCall = false;

				nexp->mLeft = exp;
				if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
				{
					nexp->mRight = ParseListExpression(false, exp->mDecType->mParams);
					ConsumeToken(TK_CLOSE_PARENTHESIS);
				}
				else
				{
					nexp->mRight = nullptr;
					mScanner->NextToken();
				}

				bool	parentCall = false;
				if (exp->mDecType->mFlags & DTF_FUNC_THIS)
				{
					if (thisExp)
					{
						if (nexp->mRight)
						{
							Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
							lexp->mLeft = thisExp;
							lexp->mRight = nexp->mRight;
							nexp->mRight = lexp;
						}
						else
							nexp->mRight = thisExp;
					}
					else
					{
						if (mThisPointer && mThisPointer->mType == DT_ARGUMENT)
						{
							Expression* texp = new Expression(mScanner->mLocation, EX_VARIABLE);
							texp->mDecType = mThisPointer->mBase;
							texp->mDecValue = mThisPointer;

							if (nexp->mRight)
							{
								Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
								lexp->mLeft = texp;
								lexp->mRight = nexp->mRight;
								nexp->mRight = lexp;
							}
							else
								nexp->mRight = texp;

							parentCall = true;
						}
					}
				}

				nexp = ResolveOverloadCall(nexp);
				Declaration* fdec = nexp->mLeft->mDecType;
				if (fdec->mType == DT_TYPE_POINTER)
					fdec = fdec->mBase;

				nexp->mDecType = fdec->mBase;

				if (fdec->mFlags & DTF_VIRTUAL)
				{
					if (parentCall)
						exp->mDecType->mFlags |= DTF_STACKCALL;
					else
						nexp->mType = EX_VCALL;
				}

				exp = nexp->ConstantFold(mErrors, mDataSection);
			}
		}
		else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC)
		{
			Expression* nexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
			nexp->mToken = mScanner->mToken;
			nexp->mLeft = exp;
			nexp->mDecType = exp->mDecType;
			mScanner->NextToken();
			exp = CheckOperatorOverload(nexp);
		}
		else if (mScanner->mToken == TK_ARROW)
		{
			mScanner->NextToken();
			if (exp->mDecType->mType != DT_TYPE_ARRAY)
			{
				while (exp->mDecType->mType != DT_TYPE_POINTER)
				{
					Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX);
					dexp->mToken = TK_ARROW;
					dexp->mDecType = TheVoidPointerTypeDeclaration;
					dexp->mLeft = exp;

					Expression* oexp = CheckOperatorOverload(dexp);
					if (oexp == dexp)
						break;
					exp = oexp;
				}
			}

			if (exp->mDecType->NonRefBase()->mType == DT_TYPE_POINTER || exp->mDecType->NonRefBase()->mType == DT_TYPE_ARRAY)
			{
				Expression * dexp = new Expression(mScanner->mLocation, EX_PREFIX);
				dexp->mToken = TK_MUL;
				dexp->mDecType = exp->mDecType->NonRefBase()->mBase;
				dexp->mLeft = exp;

				exp = ParseQualify(dexp);
/*
				if (dexp->mDecType->mType == DT_TYPE_STRUCT || dexp->mDecType->mType == DT_TYPE_UNION)
				{
					Expression* nexp = new Expression(mScanner->mLocation, EX_QUALIFY);
					nexp->mLeft = dexp;
					if (mScanner->mToken == TK_IDENT)
					{
						Declaration* mdec = dexp->mDecType->mScope->Lookup(mScanner->mTokenIdent);
						if (mdec)
						{
							if (mdec->mType == DT_ELEMENT)
							{
								nexp->mDecValue = mdec;
								nexp->mDecType = mdec->mBase;
								if (exp->mDecType->mFlags & DTF_CONST)
									nexp->mDecType = nexp->mDecType->ToConstType();

								exp = nexp->ConstantFold(mErrors);
							}
							else if (mdec->mType == DT_CONST_FUNCTION)
							{
								assert(false);
							}
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not found", mScanner->mTokenIdent);
						mScanner->NextToken();
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Struct member identifier expected");
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Struct expected");
*/
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Pointer expected");
		}
		else if (mScanner->mToken == TK_DOT)
		{
			mScanner->NextToken();

			exp = ParseQualify(exp);
		}
		else
			return exp;
	}
}


Expression* Parser::ParseNewOperator(void)
{
	Expression* nexp;

	nexp = new Expression(mScanner->mLocation, EX_PREFIX);
	nexp->mToken = TK_NEW;
	mScanner->NextToken();

	bool	placement = false;

	// Check for placement new
	if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
	{
		nexp->mType = EX_TYPECAST;
		nexp->mLeft = ParseExpression(false);

		ConsumeToken(TK_CLOSE_PARENTHESIS);
		placement = true;
	}

	Declaration* dec = ParseBaseTypeDeclaration(0, true);

	if (dec->mFlags & DTF_PURE_VIRTUAL)
		mErrors->Error(dec->mLocation, ERRR_INSTANTIATE_ABSTRACT_CLASS, "Cannot instantiate abstract class", dec->mIdent);

	Declaration* sconst = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
	sconst->mBase = TheUnsignedIntTypeDeclaration;
	sconst->mInteger = dec->mSize;

	Expression* sexp = new Expression(mScanner->mLocation, EX_CONSTANT);
	sexp->mDecValue = sconst;
	sexp->mDecType = TheUnsignedIntTypeDeclaration;

	Declaration* nudec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS);
	nudec->mBase = TheVoidPointerTypeDeclaration;
	nudec->mInteger = 0;
	Expression* nuexp = new Expression(mScanner->mLocation, EX_CONSTANT);
	nuexp->mDecValue = nudec;
	nuexp->mDecType = nudec->mBase;

	if (ConsumeTokenIf(TK_OPEN_BRACKET))
	{
		Expression* mexp = new Expression(mScanner->mLocation, EX_BINARY);
		mexp->mToken = TK_MUL;
		mexp->mLeft = sexp;
		mexp->mRight = ParseExpression(false);
		mexp->mDecType = TheUnsignedIntTypeDeclaration;
		ConsumeToken(TK_CLOSE_BRACKET);

		if (!placement)
			nexp->mLeft = mexp;

		nexp->mDecType = dec->BuildPointer(mScanner->mLocation);

		if (dec->mVectorConstructor)
		{
			Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
			vdec->mVarIndex = mLocalIndex++;
			vdec->mBase = nexp->mDecType;
			vdec->mSize = 2;

			Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
			vexp->mDecType = vdec->mBase;
			vexp->mDecValue = vdec;

			Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
			iexp->mToken = TK_ASSIGN;
			iexp->mLeft = vexp;
			iexp->mRight = nexp;
			iexp->mDecType = nexp->mDecType;

			Expression* csexp = new Expression(mScanner->mLocation, EX_TYPECAST);
			csexp->mLeft = vexp;
			csexp->mDecType = nexp->mDecType->BuildPointer(mScanner->mLocation);

			Declaration* mdec = dec->mVectorConstructor;

			Expression* pexp = new Expression(mScanner->mLocation, EX_LIST);
			pexp->mLeft = vexp;
			pexp->mRight = new Expression(mScanner->mLocation, EX_INDEX);
			pexp->mRight->mDecType = pexp->mLeft->mDecType;
			pexp->mRight->mLeft = csexp;
			pexp->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
			pexp->mRight->mRight->mDecType = TheSignedIntTypeDeclaration;
			pexp->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
			pexp->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration;
			pexp->mRight->mRight->mDecValue->mInteger = -1;

			Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			cexp->mDecValue = mdec;
			cexp->mDecType = cexp->mDecValue->mBase;

			Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
			dexp->mLeft = cexp;
			dexp->mRight = pexp;

			Expression* coexp = nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL);
			coexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
			coexp->mLeft->mDecType = TheBoolTypeDeclaration;
			coexp->mLeft->mToken = TK_EQUAL;
			coexp->mLeft->mLeft = vexp;
			coexp->mLeft->mRight = nuexp;
			coexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
			coexp->mRight->mDecType = vexp->mDecType;
			coexp->mRight->mLeft = vexp;
			coexp->mRight->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
			coexp->mRight->mRight->mDecType = vexp->mDecType;
			coexp->mRight->mRight->mLeft = dexp;
			coexp->mRight->mRight->mRight = vexp;
			coexp->mDecType = vexp->mDecType;

			Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
			sexp->mLeft = iexp;
			sexp->mRight = coexp;
			sexp->mDecType = coexp->mDecType;

			nexp = sexp;
		}
	}
	else
	{
		if (!placement)
			nexp->mLeft = sexp;

		nexp->mDecType = dec->BuildPointer(mScanner->mLocation);

		if (mScanner->mToken == TK_OPEN_PARENTHESIS || dec->mDefaultConstructor)
		{
			Declaration* mdec = dec->mDefaultConstructor;
			Expression* pexp = nullptr;

			if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
			{
				if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
				{
					pexp = ParseListExpression(false);
					ConsumeToken(TK_CLOSE_PARENTHESIS);
				}
			}

			if (dec->mType == DT_TYPE_STRUCT)
			{
				mdec = dec->mScope ? dec->mScope->Lookup(dec->mIdent->PreMangle("+")) : nullptr;
				if (pexp && pexp->mType != EX_LIST)
				{
					if (pexp->mDecType->IsSame(dec))
						mdec = dec->mCopyConstructor;
					else if (pexp->mDecType->mType == DT_TYPE_REFERENCE && pexp->mDecType->mBase->IsConstSame(dec))
						mdec = dec->mCopyConstructor;
					else if (pexp->mDecType->mType == DT_TYPE_RVALUEREF && pexp->mDecType->mBase->IsSame(dec))
					{
						if (dec->mMoveConstructor)
							mdec = dec->mMoveConstructor;
						else
							mdec = dec->mCopyConstructor;
					}
				}
			}
			else
				mdec = nullptr;

			if (mdec)
			{
				Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
				vdec->mVarIndex = mLocalIndex++;
				vdec->mBase = nexp->mDecType;
				vdec->mSize = 2;

				Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
				vexp->mDecType = vdec->mBase;
				vexp->mDecValue = vdec;

				Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
				iexp->mToken = TK_ASSIGN;
				iexp->mLeft = vexp;
				iexp->mRight = nexp;
				iexp->mDecType = nexp->mDecType;

				Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
				lexp->mLeft = vexp;
				lexp->mRight = pexp;
				pexp = lexp;

				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = mdec;
				cexp->mDecType = cexp->mDecValue->mBase;

				Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
				dexp->mLeft = cexp;
				dexp->mRight = pexp;

				dexp = ResolveOverloadCall(dexp);

				Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);

				sexp->mLeft = dexp;
				sexp->mRight = vexp;
				sexp->mDecType = vexp->mDecType;

				Expression* coexp = nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL);
				coexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
				coexp->mLeft->mDecType = TheBoolTypeDeclaration;
				coexp->mLeft->mToken = TK_EQUAL;
				coexp->mLeft->mLeft = vexp;
				coexp->mLeft->mRight = nuexp;
				coexp->mRight = new Expression(mScanner->mLocation, EX_LIST);
				coexp->mRight->mLeft = vexp;
				coexp->mRight->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
				coexp->mRight->mRight->mLeft = dexp;
				coexp->mRight->mRight->mRight = vexp;
				coexp->mDecType = vexp->mDecType;

				nexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
				nexp->mLeft = iexp;
				nexp->mRight = coexp;
				nexp->mDecType = coexp->mDecType;
			}
			else if (pexp && pexp->mType != EX_LIST)
			{
				Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX);
				dexp->mToken = TK_MUL;
				dexp->mLeft = nexp;
				dexp->mDecType = nexp->mDecType->mBase;

				Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
				iexp->mToken = TK_ASSIGN;
				iexp->mLeft = dexp;
				iexp->mRight = pexp;
				iexp->mDecType = nexp->mDecType;

				nexp = new Expression(mScanner->mLocation, EX_PREFIX);
				nexp->mToken = TK_BINARY_AND;
				nexp->mDecType = iexp->mDecType;
				nexp->mLeft = iexp;
			}
			else if (pexp)
			{
				mErrors->Error(mScanner->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching constructor", dec->mIdent);
			}
			else if (nexp->mDecType->mBase->IsSimpleType())
			{
				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);

				if (nexp->mDecType->mBase->IsIntegerType())
				{
					cexp->mDecType = TheSignedIntTypeDeclaration;
					cexp->mDecValue = TheZeroIntegerConstDeclaration;
				}
				else if (nexp->mDecType->mBase->mType == DT_TYPE_FLOAT)
				{
					cexp->mDecType = TheFloatTypeDeclaration;
					cexp->mDecValue = TheZeroFloatConstDeclaration;
				}
				else // Pointer
				{
					cexp->mDecType = TheNullPointerTypeDeclaration;
					cexp->mDecValue = TheNullptrConstDeclaration;
				}

				Expression* dexp = new Expression(mScanner->mLocation, EX_PREFIX);
				dexp->mToken = TK_MUL;
				dexp->mLeft = nexp;
				dexp->mDecType = nexp->mDecType->mBase;

				Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
				iexp->mToken = TK_ASSIGN;
				iexp->mLeft = dexp;
				iexp->mRight = cexp;
				iexp->mDecType = nexp->mDecType;

				nexp = new Expression(mScanner->mLocation, EX_PREFIX);
				nexp->mToken = TK_BINARY_AND;
				nexp->mDecType = iexp->mDecType;
				nexp->mLeft = iexp;
			}
		}
	}

	return nexp;
}

Expression* Parser::ParsePrefixExpression(bool lhs)
{
	if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_ADD ||
		mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || 
		mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND ||
		mScanner->mToken == TK_BANKOF || mScanner->mToken == TK_NEW || mScanner->mToken == TK_DELETE)
	{
		Expression* nexp;
		if (mScanner->mToken == TK_LOGICAL_NOT)
		{
			mScanner->NextToken();
			nexp = ParsePrefixExpression(false);
			nexp = nexp->LogicInvertExpression();
			nexp = CheckOperatorOverload(nexp);

		}
		else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC)
		{
			nexp = new Expression(mScanner->mLocation, EX_PREINCDEC);
			nexp->mToken = mScanner->mToken;
			mScanner->NextToken();
			nexp->mLeft = ParsePrefixExpression(false);;
			nexp->mDecType = nexp->mLeft->mDecType;
			nexp = CheckOperatorOverload(nexp);
		}
		else if (mScanner->mToken == TK_NEW)
		{
			nexp = ParseNewOperator();
		}
		else if (mScanner->mToken == TK_DELETE)
		{
			bool	vdelete = false;

			mScanner->NextToken();
			if (ConsumeTokenIf(TK_OPEN_BRACKET))
			{
				ConsumeToken(TK_CLOSE_BRACKET);
				vdelete = true;
			}

			Declaration* nudec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS);
			nudec->mBase = TheVoidPointerTypeDeclaration;
			nudec->mInteger = 0;
			Expression* nuexp = new Expression(mScanner->mLocation, EX_CONSTANT);
			nuexp->mDecValue = nudec;
			nuexp->mDecType = nudec->mBase;

			nexp = new Expression(mScanner->mLocation, EX_PREFIX);
			nexp->mToken = TK_DELETE;
			nexp->mLeft = ParsePrefixExpression(false);
			nexp->mDecType = TheVoidTypeDeclaration;
			if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER)
			{
				Declaration* dec = nexp->mLeft->mDecType->mBase;
				if (dec->mDestructor)
				{
					Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE);
					vdec->mVarIndex = mLocalIndex++;
					vdec->mBase = nexp->mLeft->mDecType;
					vdec->mSize = 2;

					Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE);
					vexp->mDecType = vdec->mBase;
					vexp->mDecValue = vdec;

					Expression* iexp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
					iexp->mToken = TK_ASSIGN;
					iexp->mLeft = vexp;
					iexp->mRight = nexp->mLeft;
					iexp->mDecType = nexp->mLeft->mDecType;

					Declaration* mdec = dec->mDestructor;
					Expression* pexp = vexp;

					if (vdelete)
					{
						mdec = dec->mVectorDestructor;

						Expression* csexp = new Expression(mScanner->mLocation, EX_TYPECAST);
						csexp->mLeft = vexp;
						csexp->mDecType = nexp->mLeft->mDecType->BuildPointer(mScanner->mLocation);

						pexp = new Expression(mScanner->mLocation, EX_LIST);
						pexp->mLeft = vexp;
						pexp->mRight = new Expression(mScanner->mLocation, EX_INDEX);
						pexp->mRight->mLeft = csexp;
						pexp->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
						pexp->mRight->mRight->mDecType = TheSignedIntTypeDeclaration;
						pexp->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
						pexp->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration;
						pexp->mRight->mRight->mDecValue->mInteger = -1;
					}

					Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					cexp->mDecValue = mdec;
					cexp->mDecType = cexp->mDecValue->mBase;

					Expression* dexp = new Expression(mScanner->mLocation, EX_CALL);
					dexp->mLeft = cexp;
					dexp->mRight = pexp;

					if (cexp->mDecValue->mBase->mFlags & DTF_VIRTUAL)
						dexp->mType = EX_VCALL;

					Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
					sexp->mLeft = iexp;
					sexp->mRight = new Expression(mScanner->mLocation, EX_IF);
					sexp->mRight->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
					sexp->mRight->mLeft->mDecType = TheBoolTypeDeclaration;
					sexp->mRight->mLeft->mToken = TK_NOT_EQUAL;
					sexp->mRight->mLeft->mLeft = vexp;
					sexp->mRight->mLeft->mRight = nuexp;
					sexp->mRight->mRight = new Expression(mScanner->mLocation, EX_LIST);
					sexp->mRight->mRight->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE);
					sexp->mRight->mRight->mLeft->mLeft = dexp;
					sexp->mRight->mRight->mLeft->mRight = nexp;
					nexp->mLeft = iexp;

					nexp = sexp;
				}
			}
		}
		else
		{
			nexp = new Expression(mScanner->mLocation, EX_PREFIX);
			nexp->mToken = mScanner->mToken;
			mScanner->NextToken();
			nexp->mLeft = ParsePrefixExpression(false);
			if (nexp->mToken == TK_MUL)
			{
				if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER || nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY)
				{
					// no pointer to function dereferencing
					if (nexp->mLeft->mDecType->mBase->mType == DT_TYPE_FUNCTION)
						return nexp->mLeft;
					nexp->mDecType = nexp->mLeft->mDecType->mBase;
				}
				else if ((mCompilerOptions & COPT_CPLUSPLUS) && nexp->mLeft->mDecType->mType == DT_TYPE_STRUCT)
				{
					nexp->mDecType = nexp->mLeft->mDecType;
				}
				else
				{
					mErrors->Error(nexp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Pointer or array type expected");
					nexp->mDecType = TheVoidTypeDeclaration;
				}
			}
			else if (nexp->mToken == TK_BINARY_AND)
			{
				nexp->mDecType = nexp->mLeft->mDecType->BuildAddressOfPointer();
			}
			else if (nexp->mToken == TK_BANKOF)
			{
				nexp->mDecType = TheSignedIntTypeDeclaration;
			}
			else if (nexp->mToken == TK_BINARY_AND)
			{
				if (nexp->mDecType->mFlags & DTF_SIGNED)
				{
					if (nexp->mDecType->mSize == 4)
						nexp->mDecType = TheUnsignedLongTypeDeclaration;
					else
						nexp->mDecType = TheUnsignedIntTypeDeclaration;
				}
				else
					nexp->mDecType = nexp->mLeft->mDecType;
			}
			else
				nexp->mDecType = nexp->mLeft->mDecType;
		}
		nexp = CheckOperatorOverload(nexp);
		return nexp->ConstantFold(mErrors, mDataSection, mCompilationUnits->mLinker);
	}
	else
		return ParsePostfixExpression(lhs);
}

static Declaration* CombinedIntType(Declaration* ld, Declaration* rd)
{
	if (ld->mSize < 2 && rd->mSize < 2)
		return TheSignedIntTypeDeclaration;
	else if (ld->mSize > rd->mSize)
		return ld;
	else if (rd->mSize > ld->mSize)
		return rd;
	else if (!(rd->mFlags & DTF_SIGNED))
		return rd;
	else
		return ld;
}

Expression* Parser::ParseMulExpression(bool lhs)
{
	Expression* exp = ParsePrefixExpression(lhs);

	while (mScanner->mToken == TK_MUL || mScanner->mToken == TK_DIV || mScanner->mToken == TK_MOD)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParsePrefixExpression(false);

		if (nexp->mLeft->mDecType->NonRefBase()->mType == DT_TYPE_FLOAT || nexp->mRight->mDecType->NonRefBase()->mType == DT_TYPE_FLOAT)
			nexp->mDecType = TheFloatTypeDeclaration;
		else if (exp->mDecType->IsIntegerType() && nexp->mRight->mDecType->IsIntegerType())
			nexp->mDecType = CombinedIntType(exp->mDecType, nexp->mRight->mDecType);
		else
			nexp->mDecType = exp->mDecType;

		exp = CheckOperatorOverload(nexp);

		exp = exp->ConstantFold(mErrors, mDataSection);
	}
	
	return exp;
}

Expression* Parser::FindPackExpression(Expression* exp)
{
	if (exp->mType == EX_PACK)
		return exp;
	
	if (exp->mLeft)
	{
		Expression* nexp = FindPackExpression(exp->mLeft);
		if (nexp)
			return nexp;
	}

	if (exp->mRight)
	{
		Expression* nexp = FindPackExpression(exp->mRight);
		if (nexp)
			return nexp;
	}

	return nullptr;
}

Expression* Parser::ExpandPackExpression(Expression* exp, Expression* pack, Expression* item)
{
	if (exp == pack)
		return item;

	Expression* left = exp->mLeft ? ExpandPackExpression(exp->mLeft, pack, item) : nullptr;
	Expression* right = exp->mRight ? ExpandPackExpression(exp->mRight, pack, item) : nullptr;

	if (left == exp->mLeft && right == exp->mRight)
		return exp;

	Expression* nexp = new Expression(exp->mLocation, exp->mType);
	nexp->mToken = exp->mToken;
	nexp->mLeft = left;
	nexp->mRight = right;
	nexp->mDecValue = exp->mDecValue;
	nexp->mDecType = exp->mDecType;

	if (nexp->mType == EX_CALL)
		nexp = ResolveOverloadCall(nexp);

	return nexp;
}

Declaration* Parser::OperatorResultType(Expression* exp)
{
	if (exp->mType == EX_BINARY)
	{
		Declaration* lt = exp->mLeft->mDecType->NonRefBase();
		Declaration* rt = exp->mRight->mDecType->NonRefBase();

		switch (exp->mToken)
		{
		case TK_MUL:
		case TK_DIV:
		case TK_MOD:
			if (lt->mType == DT_TYPE_FLOAT || rt->mType == DT_TYPE_FLOAT)
				return TheFloatTypeDeclaration;
			else
				return lt;

		case TK_ADD:
		case TK_SUB:
			if (lt->IsIndexed() && rt->IsIntegerType())
				return lt->BuildArrayPointer();
			else if (rt->IsIndexed() && lt->IsIntegerType())
				return rt->BuildArrayPointer();
			else if (lt->mType == DT_TYPE_FLOAT || rt->mType == DT_TYPE_FLOAT)
				return TheFloatTypeDeclaration;
			else if (lt->IsIndexed() && rt->IsIndexed())
				return TheSignedIntTypeDeclaration;
			else
				return lt;

		case TK_LEFT_SHIFT:
		case TK_RIGHT_SHIFT:
		case TK_BINARY_AND:
		case TK_BINARY_OR:
		case TK_BINARY_XOR:
			return lt;
		}
	}
	else if (exp->mType == EX_RELATIONAL || exp->mType == EX_LOGICAL_AND || exp->mType == EX_LOGICAL_OR || exp->mType == EX_LOGICAL_NOT)
		return TheBoolTypeDeclaration;
	else if (exp->mType == EX_LIST)
		return exp->mRight->mDecType;

	return exp->mLeft->mDecType;
}

Expression* Parser::ParseBinaryFoldExpression(Expression * exp)
{
	if (ConsumeTokenIf(exp->mToken))
		exp->mRight = ParsePrefixExpression(false);

	if (exp->mLeft)
	{
		Expression* pexp = FindPackExpression(exp->mLeft);
		if (pexp)
		{
			Declaration* dpack = pexp->mDecValue->mParams;
			Expression* nexp = exp->mRight;
			if (dpack)
			{
				dpack = dpack->Last();
				if (!nexp)
				{
					Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
					vexp->mDecType = dpack->mBase;
					vexp->mDecValue = dpack;
					nexp = ExpandPackExpression(exp->mLeft, pexp, vexp);
					dpack = dpack->mPrev;
				}

				while (dpack)
				{
					Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
					vexp->mDecType = dpack->mBase;
					vexp->mDecValue = dpack;

					Expression* oexp = new Expression(exp->mLocation, exp->mType);
					oexp->mToken = exp->mToken;
					oexp->mLeft = ExpandPackExpression(exp->mLeft, pexp, vexp);
					oexp->mRight = nexp;
					oexp->mDecType = OperatorResultType(oexp);

					nexp = CheckOperatorOverload(oexp);

					nexp = nexp->ConstantFold(mErrors, mDataSection);

					dpack = dpack->mPrev;
				}
			}

			return nexp;
		}
	}

	if (exp->mRight)
	{
		Expression* pexp = FindPackExpression(exp->mRight);
		if (pexp)
		{
			Declaration* dpack = pexp->mDecValue->mParams;
			Expression* nexp = exp->mLeft;
			if (dpack)
			{
				if (!nexp)
				{
					Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
					vexp->mDecType = dpack->mBase;
					vexp->mDecValue = dpack;
					nexp = ExpandPackExpression(exp->mRight, pexp, vexp);
					dpack = dpack->mNext;
				}

				while (dpack)
				{
					Expression* vexp = new Expression(exp->mLocation, EX_VARIABLE);
					vexp->mDecType = dpack->mBase;
					vexp->mDecValue = dpack;

					Expression* oexp = new Expression(exp->mLocation, exp->mType);
					oexp->mToken = exp->mToken;
					oexp->mLeft = nexp;
					oexp->mRight = ExpandPackExpression(exp->mRight, pexp, vexp);
					oexp->mDecType = OperatorResultType(oexp);

					nexp = CheckOperatorOverload(oexp);

					nexp = nexp->ConstantFold(mErrors, mDataSection);

					dpack = dpack->mNext;
				}
			}

			return nexp;
		}
	}

	mErrors->Error(exp->mLocation, EERR_INVALID_FOLD_EXPRESSION, "No parameter pack");
	return exp;
}

Expression* Parser::ParseAddExpression(bool lhs)
{
	Expression* exp = ParseMulExpression(lhs);

	while (mScanner->mToken == TK_ADD || mScanner->mToken == TK_SUB)
	{
		Expression * nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseMulExpression(false);
		if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER && nexp->mRight->mDecType->IsIntegerType())
		{
			if (nexp->mLeft->mDecType->mBase->mType == DT_TYPE_VOID)
			{
				if (mCompilerOptions & COPT_CPLUSPLUS)
					mErrors->Error(mScanner->mLocation, ERRR_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer");
				else
					mErrors->Error(mScanner->mLocation, EWARN_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer");
			}
			nexp->mDecType = nexp->mLeft->mDecType;
		}
		else if (nexp->mRight->mDecType->mType == DT_TYPE_POINTER && nexp->mLeft->mDecType->IsIntegerType())
		{
			if (nexp->mRight->mDecType->mBase->mType == DT_TYPE_VOID)
			{
				if (mCompilerOptions & COPT_CPLUSPLUS)
					mErrors->Error(mScanner->mLocation, ERRR_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer");
				else
					mErrors->Error(mScanner->mLocation, EWARN_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer");
			}
			nexp->mDecType = nexp->mRight->mDecType;
		}
		else if (nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY && nexp->mRight->mDecType->IsIntegerType())
		{
			Declaration* dec = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
			dec->mSize = 2;
			dec->mBase = nexp->mLeft->mDecType->mBase;
			dec->mStride = nexp->mLeft->mDecType->mStride;
			dec->mStripe = nexp->mLeft->mDecType->mStripe;
			dec->mFlags |= DTF_DEFINED;
			nexp->mDecType = dec;
		}
		else if (nexp->mRight->mDecType->mType == DT_TYPE_ARRAY && nexp->mLeft->mDecType->IsIntegerType())
		{
			Declaration* dec = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
			dec->mSize = 2;
			dec->mBase = nexp->mRight->mDecType->mBase;
			dec->mStride = nexp->mRight->mDecType->mStride;
			dec->mStripe = nexp->mRight->mDecType->mStripe;
			dec->mFlags |= DTF_DEFINED;
			nexp->mDecType = dec;
		}
		else if (nexp->mLeft->mDecType->mType == DT_TYPE_FLOAT || nexp->mRight->mDecType->mType == DT_TYPE_FLOAT)
			nexp->mDecType = TheFloatTypeDeclaration;
		else if (nexp->mToken == TK_SUB &&
			(nexp->mLeft->mDecType->mType == DT_TYPE_POINTER || nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY) &&
			(nexp->mRight->mDecType->mType == DT_TYPE_POINTER || nexp->mRight->mDecType->mType == DT_TYPE_ARRAY))
			nexp->mDecType = TheSignedIntTypeDeclaration;
		else if (exp->mDecType->IsIntegerType() && nexp->mRight->mDecType->IsIntegerType())
			nexp->mDecType = CombinedIntType(exp->mDecType, nexp->mRight->mDecType);
		else
			nexp->mDecType = exp->mDecType;

		exp = CheckOperatorOverload(nexp);

		exp = exp->ConstantFold(mErrors, mDataSection);
	}

	return exp;
}

Expression* Parser::ParseShiftExpression(bool lhs)
{
	Expression* exp = ParseAddExpression(lhs);

	while (mScanner->mToken == TK_LEFT_SHIFT || mScanner->mToken == TK_RIGHT_SHIFT)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseAddExpression(false);
		nexp->mDecType = exp->mDecType;

		exp = nexp->ConstantFold(mErrors, mDataSection);

		exp = CheckOperatorOverload(exp);
	}

	return exp;
}

Expression* Parser::ParseRelationalExpression(bool lhs)
{
	Expression* exp = ParseShiftExpression(lhs);

	while (mScanner->mToken >= TK_EQUAL && mScanner->mToken <= TK_LESS_EQUAL)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_RELATIONAL);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseShiftExpression(false);
		nexp->mDecType = TheBoolTypeDeclaration;

		exp = nexp->ConstantFold(mErrors, mDataSection);

		exp = CheckOperatorOverload(exp);
	}

	return exp;
}

Expression* Parser::ParseBinaryAndExpression(bool lhs)
{
	Expression* exp = ParseRelationalExpression(lhs);

	while (mScanner->mToken == TK_BINARY_AND)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseRelationalExpression(false);
		nexp->mDecType = exp->mDecType;

		exp = nexp->ConstantFold(mErrors, mDataSection);

		exp = CheckOperatorOverload(exp);
	}

	return exp;
}

Expression* Parser::ParseBinaryXorExpression(bool lhs)
{
	Expression* exp = ParseBinaryAndExpression(lhs);

	while (mScanner->mToken == TK_BINARY_XOR)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseBinaryAndExpression(false);
		nexp->mDecType = exp->mDecType;
		exp = nexp->ConstantFold(mErrors, mDataSection);

		exp = CheckOperatorOverload(exp);
	}

	return exp;
}

Expression* Parser::ParseBinaryOrExpression(bool lhs)
{
	Expression* exp = ParseBinaryXorExpression(lhs);

	while (mScanner->mToken == TK_BINARY_OR)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseBinaryXorExpression(false);
		nexp->mDecType = exp->mDecType;
		exp = nexp->ConstantFold(mErrors, mDataSection);

		exp = CheckOperatorOverload(exp);
	}

	return exp;
}

Expression* Parser::ParseLogicAndExpression(bool lhs)
{
	Expression* exp = ParseBinaryOrExpression(lhs);

	while (mScanner->mToken == TK_LOGICAL_AND)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_AND);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration);
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = CoerceExpression(ParseBinaryOrExpression(false), TheBoolTypeDeclaration);
		nexp->mDecType = TheBoolTypeDeclaration;
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}

	return exp;
}

Expression* Parser::ParseLogicOrExpression(bool lhs)
{
	Expression* exp = ParseLogicAndExpression(lhs);

	while (mScanner->mToken == TK_LOGICAL_OR)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_OR);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration);
		mScanner->NextToken();

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = CoerceExpression(ParseLogicAndExpression(false), TheBoolTypeDeclaration);
		nexp->mDecType = TheBoolTypeDeclaration;
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}

	return exp;
}

Expression* Parser::ParseConditionalExpression(bool lhs)
{
	Expression* exp = ParseLogicOrExpression(lhs);
	
	if (mScanner->mToken == TK_QUESTIONMARK)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL);
		nexp->mLeft = CoerceExpression(exp, TheBoolTypeDeclaration);
		mScanner->NextToken();
		Expression* texp = new Expression(mScanner->mLocation, EX_SEQUENCE);
		nexp->mRight = texp;

		texp->mLeft = ParseLogicOrExpression(false);
		ConsumeToken(TK_COLON);
		texp->mRight = ParseConditionalExpression(false);
		
		texp->mDecType = texp->mLeft->mDecType;
		nexp->mDecType = texp->mLeft->mDecType;
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}

	return exp;
}

Expression* Parser::ParseRExpression(void)
{
	return ParseConditionalExpression(false)->ConstantFold(mErrors, mDataSection);
}

Expression* Parser::ParseParenthesisExpression(void)
{
	if (mScanner->mToken == TK_OPEN_PARENTHESIS)
		mScanner->NextToken();
	else
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'(' expected");

	Expression* exp = ParseExpression(true);

	if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
		mScanner->NextToken();
	else
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected");

	return exp;
}

void Parser::ParseStaticAssert(void)
{
	if (ConsumeToken(TK_OPEN_PARENTHESIS))
	{
		Expression* exp = ParseExpression(false);
		exp = exp->ConstantFold(mErrors, mDataSection);
		if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType() && exp->mDecValue->mInteger)
		{
			if (ConsumeTokenIf(TK_COMMA))
				mScanner->NextToken();
		}
		else
		{
			if (ConsumeTokenIf(TK_COMMA) && mScanner->mToken == TK_STRING)
			{
				mErrors->Error(mScanner->mLocation, EERR_STATIC_ASSERT, "static assertion failed: ", (const char*)mScanner->mTokenString);
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_STATIC_ASSERT, "static assertion failed");
		}

		ConsumeToken(TK_CLOSE_PARENTHESIS);
	}
}

Expression* Parser::CheckOperatorOverload(Expression* exp)
{
	if (mCompilerOptions & COPT_CPLUSPLUS)
	{
		if (exp->mType == EX_ASSIGNMENT)
		{
			Declaration* tdec = exp->mLeft->mDecType;
			while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
				tdec = tdec->mBase;

			if (tdec->mType == DT_TYPE_STRUCT)
			{
				const Ident* opident = nullptr;
				switch (exp->mToken)
				{
				case TK_ASSIGN:
					opident = Ident::Unique("operator=");
					break;
				case TK_ASSIGN_ADD:
					opident = Ident::Unique("operator+=");
					break;
				case TK_ASSIGN_SUB:
					opident = Ident::Unique("operator-=");
					break;
				case TK_ASSIGN_MUL:
					opident = Ident::Unique("operator*=");
					break;
				case TK_ASSIGN_DIV:
					opident = Ident::Unique("operator/=");
					break;
				case TK_ASSIGN_MOD:
					opident = Ident::Unique("operator%=");
					break;
				case TK_ASSIGN_SHL:
					opident = Ident::Unique("operator<<=");
					break;
				case TK_ASSIGN_SHR:
					opident = Ident::Unique("operator>>=");
					break;
				case TK_ASSIGN_AND:
					opident = Ident::Unique("operator&=");
					break;
				case TK_ASSIGN_XOR:
					opident = Ident::Unique("operator^=");
					break;
				case TK_ASSIGN_OR:
					opident = Ident::Unique("operator|=");
					break;
				}

				if (opident)
				{
					Expression* nexp2 = nullptr;

					Declaration* mdec2 = mScope->Lookup(opident);
					if (mdec2)
					{
						nexp2 = new Expression(mScanner->mLocation, EX_CALL);

						nexp2->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp2->mLeft->mDecType = mdec2->mBase;
						nexp2->mLeft->mDecValue = mdec2;

						nexp2->mDecType = mdec2->mBase;
						nexp2->mRight = new Expression(mScanner->mLocation, EX_LIST); 
						nexp2->mRight->mLeft = exp->mLeft;
						nexp2->mRight->mRight = exp->mRight;
					}

					Declaration* mdec = tdec->mScope->Lookup(opident);
					if (mdec)
					{
						Expression * nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = tdec;
						texp->mDecType->mSize = 2;

						Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
						lexp->mLeft = texp->ConstantFold(mErrors, mDataSection);
						lexp->mRight = nexp->mRight;
						nexp->mRight = lexp;

						nexp = ResolveOverloadCall(nexp, nexp2);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}
			}
		}
		else if (exp->mType == EX_INITIALIZATION)
		{
			Declaration* tdec = exp->mLeft->mDecType;
			if (tdec->mType == DT_TYPE_STRUCT && exp->mToken == TK_ASSIGN)
			{
				Declaration* fcons = tdec->mScope ? tdec->mScope->Lookup(tdec->mIdent->PreMangle("+"), SLEVEL_CLASS) : nullptr;
				if (fcons)
				{
					Declaration* mtype = tdec->ToMutableType();

					Expression* vexp = exp->mLeft;

					Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
					cexp->mDecValue = fcons;
					cexp->mDecType = cexp->mDecValue->mBase;

					Expression* fexp = new Expression(mScanner->mLocation, EX_CALL);
					fexp->mLeft = cexp;
					fexp->mRight = exp->mRight;

					Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
					texp->mToken = TK_BINARY_AND;
					texp->mLeft = vexp;
					texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
					texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
					texp->mDecType->mBase = mtype;
					texp->mDecType->mSize = 2;

					if (fexp->mRight)
					{
						Expression* lexp = new Expression(mScanner->mLocation, EX_LIST);
						lexp->mLeft = texp;
						lexp->mRight = fexp->mRight;
						fexp->mRight = lexp;
					}
					else
						fexp->mRight = texp;

					fexp = ResolveOverloadCall(fexp);

					Expression* dexp = nullptr;
					if (tdec->mDestructor)
					{
						Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
						cexp->mDecValue = tdec->mDestructor;
						cexp->mDecType = cexp->mDecValue->mBase;

						dexp = new Expression(mScanner->mLocation, EX_CALL);
						dexp->mLeft = cexp;
						dexp->mRight = texp;
					}

					Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

					nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
					nexp->mLeft->mLeft = fexp;
					nexp->mLeft->mRight = dexp;

					nexp->mRight = vexp;
					nexp->mDecType = vexp->mDecType;

					exp = nexp;
				}
			}
		}
		else if (exp->mType == EX_INDEX)
		{
			Declaration* tdec = exp->mLeft->mDecType;
			while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
				tdec = tdec->mBase;

			if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope)
			{
				const Ident* opident = Ident::Unique("operator[]");

				Declaration* mdec = tdec->mScope->Lookup(opident);
				if (mdec)
				{
					Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

					nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp->mLeft->mDecType = mdec->mBase;
					nexp->mLeft->mDecValue = mdec;

					nexp->mDecType = mdec->mBase;
					nexp->mRight = exp->mRight;

					Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
					texp->mToken = TK_BINARY_AND;
					texp->mLeft = exp->mLeft;
					texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
					texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
					texp->mDecType->mBase = tdec;
					texp->mDecType->mSize = 2;

					Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
					lexp->mLeft = texp->ConstantFold(mErrors, mDataSection);
					lexp->mRight = nexp->mRight;
					nexp->mRight = lexp;

					nexp = ResolveOverloadCall(nexp);
					nexp->mDecType = nexp->mLeft->mDecType->mBase;

					exp = nexp;
				}
			}
		}
		else if (exp->mType == EX_PREINCDEC)
		{
			const Ident* opident = nullptr;
			switch (exp->mToken)
			{
			case TK_INC:
				opident = Ident::Unique("operator++");
				break;
			case TK_DEC:
				opident = Ident::Unique("operator--");
				break;
			}

			if (opident)
			{
				Declaration* tdec = exp->mLeft->mDecType;
				if (tdec->mType == DT_TYPE_STRUCT && tdec->mScope)
				{
					Declaration* mdec = tdec->mScope->Lookup(opident);
					if (mdec)
					{
						Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = exp->mLeft->mDecType;
						texp->mDecType->mSize = 2;

						nexp->mRight = texp->ConstantFold(mErrors, mDataSection);

						nexp = ResolveOverloadCall(nexp);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}
			}
		}
		else if (exp->mType == EX_POSTINCDEC)
		{
			const Ident* opident = nullptr;
			switch (exp->mToken)
			{
			case TK_INC:
				opident = Ident::Unique("operator++");
				break;
			case TK_DEC:
				opident = Ident::Unique("operator--");
				break;
			}

			if (opident)
			{
				Declaration* tdec = exp->mLeft->mDecType;
				if (tdec->mType == DT_TYPE_STRUCT)
				{
					Declaration* mdec = tdec->mScope->Lookup(opident);
					if (mdec)
					{
						Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = exp->mLeft->mDecType;
						texp->mDecType->mSize = 2;

						Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
						lexp->mLeft = texp->ConstantFold(mErrors, mDataSection);
						lexp->mRight = new Expression(nexp->mLocation, EX_CONSTANT);
						lexp->mRight->mDecType = TheSignedIntTypeDeclaration;
						lexp->mRight->mDecValue = new Declaration(nexp->mLocation, DT_CONST_INTEGER);
						lexp->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration;
						nexp->mRight = lexp;

						nexp = ResolveOverloadCall(nexp);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}
			}
		}
		else if (exp->mType == EX_BINARY || exp->mType == EX_RELATIONAL)
		{
			const Ident* opident = nullptr;
			switch (exp->mToken)
			{
			case TK_ADD:
				opident = Ident::Unique("operator+");
				break;
			case TK_SUB:
				opident = Ident::Unique("operator-");
				break;
			case TK_MUL:
				opident = Ident::Unique("operator*");
				break;
			case TK_DIV:
				opident = Ident::Unique("operator/");
				break;
			case TK_MOD:
				opident = Ident::Unique("operator%");
				break;
			case TK_BINARY_AND:
				opident = Ident::Unique("operator&");
				break;
			case TK_BINARY_OR:
				opident = Ident::Unique("operator|");
				break;
			case TK_BINARY_XOR:
				opident = Ident::Unique("operator^");
				break;
			case TK_LEFT_SHIFT:
				opident = Ident::Unique("operator<<");
				break;
			case TK_RIGHT_SHIFT:
				opident = Ident::Unique("operator>>");
				break;
			case TK_EQUAL:
				opident = Ident::Unique("operator==");
				break;
			case TK_NOT_EQUAL:
				opident = Ident::Unique("operator!=");
				break;
			case TK_GREATER_THAN:
				opident = Ident::Unique("operator>");
				break;
			case TK_GREATER_EQUAL:
				opident = Ident::Unique("operator>=");
				break;
			case TK_LESS_THAN:
				opident = Ident::Unique("operator<");
				break;
			case TK_LESS_EQUAL:
				opident = Ident::Unique("operator<=");
				break;
			}

			if (opident)
			{
				Expression* nexp2 = nullptr;

				Declaration* mdec2 = mScope->Lookup(opident);
				if (mdec2)
				{
					nexp2 = new Expression(mScanner->mLocation, EX_CALL);

					nexp2->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp2->mLeft->mDecType = mdec2->mBase;
					nexp2->mLeft->mDecValue = mdec2;

					nexp2->mDecType = mdec2->mBase;
					nexp2->mRight = new Expression(mScanner->mLocation, EX_LIST);
					nexp2->mRight->mLeft = exp->mLeft;
					nexp2->mRight->mRight = exp->mRight;
				}

				Declaration* tdec = exp->mLeft->mDecType;
				while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
					tdec = tdec->mBase;
				Declaration* rtdec = exp->mRight->mDecType;
				while (rtdec->mType == DT_TYPE_REFERENCE || rtdec->mType == DT_TYPE_RVALUEREF)
					rtdec = rtdec->mBase;

				if (tdec->mType == DT_TYPE_STRUCT)
				{
					Declaration* mdec = tdec->mScope->Lookup(opident);
					if (mdec)
					{
						Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = tdec;
						texp->mDecType->mSize = 2;

						Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
						lexp->mLeft = texp->ConstantFold(mErrors, mDataSection);
						lexp->mRight = nexp->mRight;
						nexp->mRight = lexp;

						nexp = ResolveOverloadCall(nexp, nexp2);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}

				if (exp->mType != EX_CALL && !nexp2 && (tdec->mType == DT_TYPE_STRUCT || rtdec->mType == DT_TYPE_STRUCT))
				{
					if ((exp->mLeft->mDecType->IsIntegerType() || CanCoerceExpression(exp->mLeft, TheSignedIntTypeDeclaration)) && 
						(exp->mRight->mDecType->IsIntegerType() || CanCoerceExpression(exp->mRight, TheSignedIntTypeDeclaration)))
					{
						exp->mLeft = CoerceExpression(exp->mLeft, TheSignedIntTypeDeclaration);
						exp->mRight = CoerceExpression(exp->mRight, TheSignedIntTypeDeclaration);
						if (exp->mType == EX_BINARY)
							exp->mDecType = TheSignedIntTypeDeclaration;
					}
				}
			}
		}
		else if (exp->mType == EX_PREFIX)
		{
			const Ident* opident = nullptr;
			switch (exp->mToken)
			{
			case TK_ADD:
				opident = Ident::Unique("operator+");
				break;
			case TK_SUB:
				opident = Ident::Unique("operator-");
				break;
			case TK_MUL:
				opident = Ident::Unique("operator*");
				break;
			case TK_BINARY_NOT:
				opident = Ident::Unique("operator~");
				break;
			case TK_ARROW:
				opident = Ident::Unique("operator->");
				break;
			}

			if (opident)
			{
				Declaration* tdec = exp->mLeft->mDecType;
				while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
					tdec = tdec->mBase;

				if (tdec->mType == DT_TYPE_STRUCT)
				{
					Declaration* mdec = tdec->mScope->Lookup(opident);
					if (mdec)
					{
						Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = tdec;
						texp->mDecType->mSize = 2;

						nexp->mRight = texp->ConstantFold(mErrors, mDataSection);

						nexp = ResolveOverloadCall(nexp);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}
			}
		}
		else if (exp->mType == EX_TYPECAST)
		{
			Declaration* tdec = exp->mLeft->mDecType;
			if (exp->mLeft->mDecType)
			{
				while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
					tdec = tdec->mBase;

				if (tdec->mType == DT_TYPE_STRUCT)
				{
					Declaration* mdec = tdec->mScope->Lookup(Ident::Unique("(cast)"));
					while (mdec && !mdec->mBase->mBase->IsSame(exp->mDecType))
						mdec = mdec->mNext;
					while (!mdec && tdec->mBase && tdec->mBase->mBase)
					{
						tdec = tdec->mBase->mBase;
						mdec = tdec->mScope->Lookup(Ident::Unique("(cast)"));
						while (mdec && !mdec->mBase->mBase->IsSame(exp->mDecType))
							mdec = mdec->mNext;
					}

					if (mdec)
					{
						Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

						nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
						nexp->mLeft->mDecType = mdec->mBase;
						nexp->mLeft->mDecValue = mdec;

						nexp->mDecType = mdec->mBase;
						nexp->mRight = exp->mRight;

						Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
						texp->mToken = TK_BINARY_AND;
						texp->mLeft = exp->mLeft;
						texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
						texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
						texp->mDecType->mBase = tdec;
						texp->mDecType->mSize = 2;

						nexp->mRight = texp->ConstantFold(mErrors, mDataSection);

						nexp = ResolveOverloadCall(nexp);
						nexp->mDecType = nexp->mLeft->mDecType->mBase;

						exp = nexp;
					}
				}
			}
		}
		else if (exp->mType == EX_LOGICAL_NOT)
		{
			const Ident* opident = Ident::Unique("operator!");
			Declaration* tdec = exp->mLeft->mDecType;
			while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
				tdec = tdec->mBase;

			if (tdec->mType == DT_TYPE_STRUCT)
			{
				Declaration* mdec = tdec->mScope->Lookup(opident);
				if (mdec)
				{
					Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);

					nexp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
					nexp->mLeft->mDecType = mdec->mBase;
					nexp->mLeft->mDecValue = mdec;

					nexp->mDecType = mdec->mBase;
					nexp->mRight = exp->mRight;

					Expression* texp = new Expression(nexp->mLocation, EX_PREFIX);
					texp->mToken = TK_BINARY_AND;
					texp->mLeft = exp->mLeft;
					texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
					texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
					texp->mDecType->mBase = tdec;
					texp->mDecType->mSize = 2;

					nexp->mRight = texp->ConstantFold(mErrors, mDataSection);

					nexp = ResolveOverloadCall(nexp);
					nexp->mDecType = nexp->mLeft->mDecType->mBase;

					exp = nexp;
				}
			}
		}
	}

	return exp;
}

Expression* Parser::ParseAssignmentExpression(bool lhs)
{
	Expression* exp = ParseConditionalExpression(lhs);

	if (mScanner->mToken >= TK_ASSIGN && mScanner->mToken <= TK_ASSIGN_OR)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssignmentExpression(false);
		nexp->mDecType = exp->mDecType;

		exp = CheckOperatorOverload(nexp);

		assert(exp->mDecType);
	}

	return exp;
}

Expression* Parser::ParseExpression(bool lhs)
{
	return ParseAssignmentExpression(lhs);
}

Expression* Parser::ExpandArgumentPack(Expression* exp, Declaration* dec)
{
	Expression* vex = new Expression(exp->mLocation, EX_VARIABLE);
	vex->mDecType = dec->mBase;
	vex->mDecValue = dec;

	if (dec->mNext)
	{
		Expression* lex = new Expression(exp->mLocation, EX_LIST);
		lex->mToken = TK_COMMA;
		lex->mLeft = vex;
		lex->mRight = ExpandArgumentPack(exp, dec->mNext);
		return lex;
	}
	else
		return vex;
}

Expression* Parser::ParseListExpression(bool lhs, Declaration* params)
{
	if (ConsumeTokenIf(TK_ELLIPSIS))
	{
		ExpressionType	et = EX_ERROR;
		switch (mScanner->mToken)
		{
		case TK_MUL:
		case TK_DIV:
		case TK_MOD:
		case TK_ADD:
		case TK_SUB:
		case TK_LEFT_SHIFT:
		case TK_RIGHT_SHIFT:
		case TK_BINARY_AND:
		case TK_BINARY_OR:
		case TK_BINARY_XOR:
			et = EX_BINARY;
			break;
		case TK_EQUAL:
		case TK_NOT_EQUAL:
		case TK_GREATER_THAN:
		case TK_GREATER_EQUAL:
		case TK_LESS_THAN:
		case TK_LESS_EQUAL:
			et = EX_RELATIONAL;
			break;
		case TK_LOGICAL_AND:
			et = EX_LOGICAL_AND;
			break;
		case TK_LOGICAL_OR:
			et = EX_LOGICAL_OR;
			break;
		case TK_LOGICAL_NOT:
			et = EX_LOGICAL_NOT;
			break;
		case TK_COMMA:
			et = EX_LIST;
			break;
		}

		if (et == EX_ERROR)
			mErrors->Error(mScanner->mLocation, EERR_INVALID_FOLD_EXPRESSION, "Invalid operator in fold expression");

		Expression* nexp = new Expression(mScanner->mLocation, et);
		nexp->mToken = mScanner->mToken;
		mScanner->NextToken();
		nexp->mRight = ParseExpression(false);
		return ParseBinaryFoldExpression(nexp);
	}

	Expression* exp;
	
	if ((mCompilerOptions & COPT_CPLUSPLUS) && mScanner->mToken == TK_OPEN_BRACE && params)
	{
		exp = new Expression(mScanner->mLocation, EX_TYPE);
		exp->mDecType = params->mBase->NonRefBase();
		exp = ParseCastExpression(exp);
	}
	else
		exp = ParseExpression(lhs);

	if (exp->mType == EX_PACK)
	{
		if (ConsumeTokenIf(TK_ELLIPSIS))
		{
			if (exp->mDecValue->mParams)
				exp = ExpandArgumentPack(exp, exp->mDecValue->mParams);
			else
				exp = nullptr;
		}
	}

	if (ConsumeTokenIf(TK_COMMA))
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_LIST);
		nexp->mToken = TK_COMMA;
		nexp->mLeft = exp;

		if (ConsumeTokenIf(TK_ELLIPSIS))
			return ParseBinaryFoldExpression(nexp);

		nexp->mRight = ParseListExpression(false, params ? params->mNext : nullptr);
		nexp->mDecType = nexp->mRight->mDecType;
		exp = nexp;
	}
	return exp;

}

Expression* Parser::ParseFunction(Declaration * dec)
{
	Declaration* othis = mThisPointer;
	Declaration* ofunc = mFunctionType;

	if (dec->mFlags & DTF_FUNC_THIS)
		mThisPointer = dec->mParams;
	else
		mThisPointer = dec->mClass;

	mFunctionType = dec;

	DeclarationScope* oscope = mScope;
	while (mScope->mLevel == SLEVEL_CLASS)
		mScope = mScope->mParent;

	DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_FUNCTION);
	mScope = scope;

	Declaration* pdec = dec->mParams;
	while (pdec)
	{
		if (pdec->mIdent)
			scope->Insert(pdec->mIdent, pdec);
		pdec = pdec->mNext;
	}
	if (dec->mParamPack)
		mScope->Insert(dec->mParamPack->mIdent, dec->mParamPack);
	mLocalIndex = 0;
	mTempVars = nullptr;

	Expression * exp = ParseStatement();

	if (mCompilerOptions & COPT_CPLUSPLUS)
	{
		// Add destructors for parameters
		Declaration* pdec = dec->mParams;

		while (pdec)
		{
			if (pdec->mBase->mType == DT_TYPE_STRUCT && pdec->mBase->mDestructor)
			{
				Expression* vexp = new Expression(pdec->mLocation, EX_VARIABLE);
				vexp->mDecType = pdec->mBase;
				vexp->mDecValue = pdec;

				Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX);
				texp->mToken = TK_BINARY_AND;
				texp->mLeft = vexp;
				texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
				texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
				texp->mDecType->mBase = pdec->mBase;
				texp->mDecType->mSize = 2;

				Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT);
				cexp->mDecValue = pdec->mBase->mDestructor;
				cexp->mDecType = cexp->mDecValue->mBase;
				
				Expression * dexp = new Expression(mScanner->mLocation, EX_CALL);
				dexp->mLeft = cexp;
				dexp->mRight = texp;

				Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT);

				nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST);
				nexp->mLeft->mLeft = nullptr;
				nexp->mLeft->mRight = dexp;
				nexp->mRight = vexp;
				nexp->mDecType = vexp->mDecType;

				Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
				sexp->mLeft = nexp;
				sexp->mRight = exp;
				exp = sexp;
			}

			pdec = pdec->mNext;
		}
	}

	if (!dec->mBase)
		dec->mBase = TheVoidTypeDeclaration;
	else if (dec->mBase->mType == DT_TYPE_AUTO)
		dec->mBase->mType = DT_TYPE_VOID;

	mScope->End(mScanner->mLocation);
	mScope = oscope;

	mThisPointer = othis;
	mFunctionType = ofunc;

	return exp;
}

void Parser::SkipStatement(void)
{
	if (ConsumeTokenIf(TK_OPEN_BRACE))
	{
		int cnt = 1;
		while (cnt > 0)
		{
			if (ConsumeTokenIf(TK_OPEN_BRACE))
				cnt++;
			else if (ConsumeTokenIf(TK_CLOSE_BRACE))
				cnt--;
			else
				mScanner->NextToken();
		}
	}
	else if (ConsumeTokenIf(TK_IF))
	{
		SkipStatement();
		if (ConsumeTokenIf(TK_ELSE))
			SkipStatement();
	}
	else
	{
		while (!ConsumeTokenIf(TK_SEMICOLON))
		{
			mScanner->NextToken();
		} 
	}
}

Expression* Parser::ParseStatement(void)
{
	Expression* exp = nullptr;

	while (mScanner->mToken == TK_PREP_PRAGMA)
	{
		mScanner->NextToken();
		ParsePragma();
		if (mScanner->mToken == TK_CLOSE_BRACE)
			return nullptr;
	}
	
	if (mScanner->mToken == TK_OPEN_BRACE)
	{
		DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_LOCAL);
		mScope = scope;

		mScanner->NextToken();
		if (mScanner->mToken != TK_CLOSE_BRACE)
		{
			Expression* sexp = new Expression(mScanner->mLocation, EX_SCOPE);

			Expression* pexp = nullptr;
			do
			{
				Expression* nexp = ParseStatement();
				if (nexp)
				{
					if (exp)
					{
						if (!pexp)
						{
							pexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
							pexp->mLeft = exp;
							exp = pexp;
						}

						pexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
						pexp = pexp->mRight;
						pexp->mLeft = nexp;
					}
					else
						exp = nexp;
				}

			} while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF);

			if (mScanner->mToken != TK_CLOSE_BRACE)
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");

			exp->mEndLocation = mScanner->mLocation;
			sexp->mEndLocation = mScanner->mLocation;
			mScope->End(mScanner->mLocation);
			mScanner->NextToken();

			sexp->mLeft = exp;

			exp = sexp;
		}
		else
		{
			exp = new Expression(mScanner->mLocation, EX_VOID);
			exp->mEndLocation = mScanner->mLocation;
			mScanner->NextToken();
		}

		mScope = mScope->mParent;
	}
	else
	{
		switch (mScanner->mToken)
		{
		case TK_IF:
		{
			mScanner->NextToken();

			if (ConsumeTokenIf(TK_CONSTEXPR))
			{
				exp = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration)->ConstantFold(mErrors, mDataSection);
				if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
				{
					if (exp->mDecValue->mInteger)
					{
						exp = ParseStatement();
						if (ConsumeTokenIf(TK_ELSE))
							SkipStatement();
					}
					else
					{
						SkipStatement();
						if (ConsumeTokenIf(TK_ELSE))
							exp = ParseStatement();
						else
							exp = new Expression(mScanner->mLocation, EX_VOID);
					}
				}
				else
					mErrors->Error(exp->mLocation, EERR_INVALID_CONSTEXPR, "Condition is not constant");
			}
			else
			{
				exp = new Expression(mScanner->mLocation, EX_IF);
				exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration);
				exp->mRight = new Expression(mScanner->mLocation, EX_ELSE);
				exp->mRight->mLeft = ParseStatement();
				if (mScanner->mToken == TK_ELSE)
				{
					mScanner->NextToken();
					exp->mRight->mRight = ParseStatement();
				}
				else
					exp->mRight->mRight = nullptr;
			}
		
		}	break;
		case TK_WHILE:
		{
			mScanner->NextToken();

			DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_LOCAL);
			mScope = scope;

			exp = new Expression(mScanner->mLocation, EX_WHILE);
			exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration);
			exp->mRight = ParseStatement();

			mScope->End(mScanner->mLocation);
			mScope = mScope->mParent;
		}
			break;
		case TK_DO:
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_DO);
			exp->mRight = ParseStatement();
			if (mScanner->mToken == TK_WHILE)
			{
				mScanner->NextToken();
				exp->mLeft = CoerceExpression(CleanupExpression(ParseParenthesisExpression()), TheBoolTypeDeclaration);
				ConsumeToken(TK_SEMICOLON);
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'while' expected");
			break;
		case TK_FOR:
			mScanner->NextToken();
			if (mScanner->mToken == TK_OPEN_PARENTHESIS)
			{
				DeclarationScope* scope = new DeclarationScope(mScope, SLEVEL_LOCAL);
				mScope = scope;

				mScanner->NextToken();
				exp = new Expression(mScanner->mLocation, EX_FOR);

				int		unrollLoop = mUnrollLoop;
				bool	unrollPage = mUnrollLoopPage;
				mUnrollLoop = 0;
				mUnrollLoopPage = false;

				Expression* initExp = nullptr, * iterateExp = nullptr, * conditionExp = nullptr, * bodyExp = nullptr, * finalExp = nullptr;

				// Assignment
				if (mScanner->mToken != TK_SEMICOLON)
					initExp = CleanupExpression(ParseListExpression(true));

				if ((mCompilerOptions & COPT_CPLUSPLUS) && ConsumeTokenIf(TK_COLON))
				{
					Expression* containerExp = ParseExpression(false);
					if (initExp->mType == EX_VARIABLE)
					{
						if (containerExp->mDecType->mType == DT_TYPE_ARRAY)
						{
							Declaration* iterVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE);
							iterVarDec->mBase = containerExp->mDecType->mBase->BuildPointer(mScanner->mLocation);
							iterVarDec->mBase = containerExp->mDecType->mBase->BuildPointer(mScanner->mLocation);
							iterVarDec->mVarIndex = mLocalIndex++;
							iterVarDec->mSize = iterVarDec->mBase->mSize;
							iterVarDec->mFlags |= DTF_DEFINED;

							Declaration* endVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE);
							endVarDec->mBase = iterVarDec->mBase;
							endVarDec->mVarIndex = mLocalIndex++;
							endVarDec->mSize = endVarDec->mBase->mSize;
							endVarDec->mFlags |= DTF_DEFINED;

							Declaration* valueVarDec = initExp->mDecValue;
							valueVarDec->mBase = valueVarDec->mBase->DeduceAuto(containerExp->mDecType->mBase);
							valueVarDec->mSize = valueVarDec->mBase->mSize;

							initExp = new Expression(mScanner->mLocation, EX_LIST);
							initExp->mLeft = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							initExp->mLeft->mToken = TK_ASSIGN;
							initExp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							initExp->mLeft->mLeft->mDecType = iterVarDec->mBase;
							initExp->mLeft->mLeft->mDecValue = iterVarDec;
							initExp->mLeft->mRight = containerExp;

							initExp->mRight = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							initExp->mRight->mToken = TK_ASSIGN;
							initExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							initExp->mRight->mLeft->mDecType = endVarDec->mBase;
							initExp->mRight->mLeft->mDecValue = endVarDec;
							initExp->mRight->mRight = new Expression(mScanner->mLocation, EX_BINARY);
							initExp->mRight->mRight->mToken = TK_ADD;
							initExp->mRight->mRight->mDecType = iterVarDec->mBase;
							initExp->mRight->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							initExp->mRight->mRight->mLeft->mDecType = iterVarDec->mBase;
							initExp->mRight->mRight->mLeft->mDecValue = iterVarDec;
							initExp->mRight->mRight->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
							initExp->mRight->mRight->mRight->mDecType = TheSignedIntTypeDeclaration;
							initExp->mRight->mRight->mRight->mDecValue = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
							initExp->mRight->mRight->mRight->mDecValue->mBase = TheSignedIntTypeDeclaration;
							initExp->mRight->mRight->mRight->mDecValue->mSize = 2;
							initExp->mRight->mRight->mRight->mDecValue->mInteger = containerExp->mDecType->mSize / containerExp->mDecType->mBase->mSize;

							iterateExp = new Expression(mScanner->mLocation, EX_PREINCDEC);
							iterateExp->mToken = TK_INC;
							iterateExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							iterateExp->mLeft->mDecType = iterVarDec->mBase;
							iterateExp->mLeft->mDecValue = iterVarDec;

							conditionExp = new Expression(mScanner->mLocation, EX_RELATIONAL);
							conditionExp->mToken = TK_NOT_EQUAL;
							conditionExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							conditionExp->mLeft->mDecType = iterVarDec->mBase;
							conditionExp->mLeft->mDecValue = iterVarDec;
							conditionExp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE);
							conditionExp->mRight->mDecType = endVarDec->mBase;
							conditionExp->mRight->mDecValue = endVarDec;

							if (valueVarDec->mBase->IsReference())
								bodyExp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
							else
								bodyExp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
							bodyExp->mToken = TK_ASSIGN;
							bodyExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							bodyExp->mLeft->mDecType = valueVarDec->mBase;
							bodyExp->mLeft->mDecValue = valueVarDec;
							bodyExp->mRight = new Expression(mScanner->mLocation, EX_PREFIX);
							bodyExp->mRight->mToken = TK_MUL;
							bodyExp->mRight->mDecType = containerExp->mDecType->mBase;
							bodyExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
							bodyExp->mRight->mLeft->mDecType = iterVarDec->mBase;
							bodyExp->mRight->mLeft->mDecValue = iterVarDec;
						}
						else if (containerExp->mDecType->mType == DT_TYPE_STRUCT)
						{
							Declaration* fbegin = containerExp->mDecType->mScope->Lookup(Ident::Unique("begin"));
							Declaration* fend = containerExp->mDecType->mScope->Lookup(Ident::Unique("end"));

							if (fbegin && fend)
							{
								Expression* cexp = new Expression(mScanner->mLocation, EX_PREFIX);
								cexp->mToken = TK_BINARY_AND;
								cexp->mDecType = containerExp->mDecType->BuildPointer(mScanner->mLocation);
								cexp->mLeft = containerExp;

								Expression* cbegin = new Expression(mScanner->mLocation, EX_CALL);
								cbegin->mDecType = fbegin->mBase->mBase;
								cbegin->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
								cbegin->mLeft->mDecType = fbegin->mBase;
								cbegin->mLeft->mDecValue = fbegin;
								cbegin->mRight = cexp;

								Expression* cend = new Expression(mScanner->mLocation, EX_CALL);
								cend->mDecType = fend->mBase->mBase;
								cend->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
								cend->mLeft->mDecType = fend->mBase;
								cend->mLeft->mDecValue = fend;
								cend->mRight = cexp;

								ResolveOverloadCall(cbegin);
								ResolveOverloadCall(cend);

								fbegin = cbegin->mLeft->mDecValue;
								fend = cend->mLeft->mDecValue;

								cbegin->mDecType = fbegin->mBase->mBase;
								cend->mDecType = fend->mBase->mBase;

								Declaration* iterVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE);
								iterVarDec->mBase = fbegin->mBase->mBase->NonRefBase();
								iterVarDec->mVarIndex = mLocalIndex++;
								iterVarDec->mSize = iterVarDec->mBase->mSize;
								iterVarDec->mFlags |= DTF_DEFINED;

								Declaration* endVarDec = new Declaration(mScanner->mLocation, DT_VARIABLE);
								endVarDec->mBase = fend->mBase->mBase->NonRefBase();
								endVarDec->mVarIndex = mLocalIndex++;
								endVarDec->mSize = endVarDec->mBase->mSize;
								endVarDec->mFlags |= DTF_DEFINED;

								Declaration* valueVarDec = initExp->mDecValue;

								initExp = new Expression(mScanner->mLocation, EX_LIST);
								initExp->mLeft = new Expression(mScanner->mLocation, EX_INITIALIZATION);
								initExp->mLeft->mToken = TK_ASSIGN;
								initExp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
								initExp->mLeft->mLeft->mDecType = iterVarDec->mBase;
								initExp->mLeft->mLeft->mDecValue = iterVarDec;
								initExp->mLeft->mRight = cbegin;

								initExp->mRight = new Expression(mScanner->mLocation, EX_INITIALIZATION);
								initExp->mRight->mToken = TK_ASSIGN;
								initExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
								initExp->mRight->mLeft->mDecType = endVarDec->mBase;
								initExp->mRight->mLeft->mDecValue = endVarDec;
								initExp->mRight->mRight = cend;

								iterateExp = new Expression(mScanner->mLocation, EX_PREINCDEC);
								iterateExp->mToken = TK_INC;
								iterateExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
								iterateExp->mLeft->mDecType = iterVarDec->mBase;
								iterateExp->mLeft->mDecValue = iterVarDec;
								iterateExp = CheckOperatorOverload(iterateExp);

								conditionExp = new Expression(mScanner->mLocation, EX_RELATIONAL);
								conditionExp->mToken = TK_NOT_EQUAL;
								conditionExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
								conditionExp->mLeft->mDecType = iterVarDec->mBase;
								conditionExp->mLeft->mDecValue = iterVarDec;
								conditionExp->mRight = new Expression(mScanner->mLocation, EX_VARIABLE);
								conditionExp->mRight->mDecType = endVarDec->mBase;
								conditionExp->mRight->mDecValue = endVarDec;
								conditionExp = CheckOperatorOverload(conditionExp);

								bodyExp = new Expression(mScanner->mLocation, EX_INITIALIZATION);
								bodyExp->mToken = TK_ASSIGN;
								bodyExp->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);

								bodyExp->mRight = new Expression(mScanner->mLocation, EX_PREFIX);
								bodyExp->mRight->mToken = TK_MUL;
								bodyExp->mRight->mDecType = valueVarDec->mBase;
								bodyExp->mRight->mLeft = new Expression(mScanner->mLocation, EX_VARIABLE);
								bodyExp->mRight->mLeft->mDecType = iterVarDec->mBase;
								bodyExp->mRight->mLeft->mDecValue = iterVarDec;
								if (iterVarDec->mBase->mType == DT_TYPE_POINTER)
									bodyExp->mRight->mDecType = iterVarDec->mBase->mBase;
								else
									bodyExp->mRight = CheckOperatorOverload(bodyExp->mRight);

								valueVarDec->mBase = valueVarDec->mBase->DeduceAuto(bodyExp->mRight->mDecType);
								valueVarDec->mSize = valueVarDec->mBase->mSize;

								bodyExp->mLeft->mDecType = valueVarDec->mBase;
								bodyExp->mLeft->mDecValue = valueVarDec;
								bodyExp = CheckOperatorOverload(bodyExp);
							}
							else
								mErrors->Error(containerExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Array or container expected");
						}
						else
							mErrors->Error(containerExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Array or container expected");
					}
					else
						mErrors->Error(initExp->mLocation, EERR_INCOMPATIBLE_TYPES, "Variable expected");
				}
				else
				{
					if (mScanner->mToken == TK_SEMICOLON)
						mScanner->NextToken();
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected");

					// Condition
					if (mScanner->mToken != TK_SEMICOLON)
						conditionExp = CoerceExpression(CleanupExpression(ParseListExpression(false)), TheBoolTypeDeclaration);

					if (mScanner->mToken == TK_SEMICOLON)
						mScanner->NextToken();
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected");

					// Iteration
					if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
						iterateExp = CleanupExpression(ParseListExpression(false));
				}

				ConsumeToken(TK_CLOSE_PARENTHESIS);

				Expression * innerExp = ParseStatement();
				if (bodyExp)
				{
					Expression* exp = new Expression(bodyExp->mLocation, EX_SEQUENCE);
					exp->mLeft = bodyExp;
					exp->mRight = innerExp;
					bodyExp = exp;
				}
				else
					bodyExp = innerExp;

				mScope->End(mScanner->mLocation);

				exp->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE);
				exp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE);

				if (unrollLoop > 1 && initExp && iterateExp && conditionExp)
				{
					if ((initExp->mType == EX_ASSIGNMENT || initExp->mType == EX_INITIALIZATION) && initExp->mLeft->mType == EX_VARIABLE && initExp->mRight->mType == EX_CONSTANT &&
						(iterateExp->mType == EX_POSTINCDEC || iterateExp->mType == EX_PREINCDEC || iterateExp->mType == EX_ASSIGNMENT && (iterateExp->mToken == TK_ASSIGN_ADD || iterateExp->mToken == TK_ASSIGN_SUB) && iterateExp->mRight->mType == EX_CONSTANT) && 
						iterateExp->mLeft->IsSame(initExp->mLeft) &&
						(conditionExp->mType == EX_RELATIONAL && 
							(conditionExp->mToken == TK_LESS_THAN || conditionExp->mToken == TK_GREATER_THAN || conditionExp->mToken == TK_LESS_EQUAL || conditionExp->mToken == TK_GREATER_EQUAL) && 
							conditionExp->mLeft->IsSame(initExp->mLeft) && 
							conditionExp->mRight->mType == EX_CONSTANT ||
						 conditionExp->IsSame(initExp->mLeft)))
					{
						if (initExp->mRight->mDecValue->mType == DT_CONST_INTEGER && (conditionExp->mType == EX_VARIABLE || conditionExp->mRight->mDecValue->mType == DT_CONST_INTEGER))
						{
							int	startValue = int(initExp->mRight->mDecValue->mInteger);
							int	endValue = 0;
							int	stepValue = 1;

							if (iterateExp->mType == EX_ASSIGNMENT)
							{
								if (iterateExp->mToken == TK_ASSIGN_ADD)
									stepValue = int(iterateExp->mRight->mDecValue->mInteger);
								else
									stepValue = - int(iterateExp->mRight->mDecValue->mInteger);
							}
							else if (iterateExp->mToken == TK_DEC)
								stepValue = -1;

							if (conditionExp->mType == EX_RELATIONAL)
							{
								endValue = int(conditionExp->mRight->mDecValue->mInteger);

								if (conditionExp->mToken == TK_LESS_EQUAL)
								{
									endValue++;
									conditionExp->mToken = TK_LESS_THAN;
								}
								else if (conditionExp->mToken == TK_GREATER_EQUAL)
								{
									endValue--;
									conditionExp->mToken = TK_GREATER_THAN;
								}
							}
							else if (stepValue > 0 && startValue >= 0)
							{
								endValue = 1 << (initExp->mLeft->mDecValue->mSize * 8);
							}

							if (unrollPage)
							{
								int numLoops = (endValue - startValue + 255) / 256;
								int	numIterations = (endValue - startValue) / numLoops;
								int	stride = (endValue - startValue) / numLoops;
								int	remain = (endValue - startValue) - numIterations * numLoops;

								// Switch from 3 to 4 to avoid cost of two remains
								if (numLoops == 3 && remain == 2 && !((endValue - startValue) & 3))
								{
									numLoops = 4;
									numIterations = (endValue - startValue) / numLoops;
									stride = (endValue - startValue) / numLoops;
									remain = (endValue - startValue) - numIterations * numLoops;
								}

								Expression* unrollBody = new Expression(mScanner->mLocation, EX_SEQUENCE);
								unrollBody->mLeft = bodyExp;
								Expression* bexp = unrollBody;
								
								Expression*	iexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
								iexp->mToken = TK_ASSIGN_ADD;
								iexp->mLeft = iterateExp->mLeft;
								iexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);

								Declaration	*	idec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								idec->mInteger = stride;
								idec->mBase = TheSignedIntTypeDeclaration;
								iexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								iexp->mRight->mDecValue = idec;
								iexp->mRight->mDecType = idec->mBase;

								Expression* dexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
								dexp->mToken = TK_ASSIGN_SUB;
								dexp->mLeft = iterateExp->mLeft;
								dexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);

								Declaration* ddec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
								ddec->mInteger = stride * (numLoops - 1);
								ddec->mBase = TheSignedIntTypeDeclaration;
								dexp->mRight = new Expression(mScanner->mLocation, EX_CONSTANT);
								dexp->mRight->mDecValue = ddec;
								dexp->mRight->mDecType = ddec->mBase;

								for (int i = 1; i < numLoops; i++)
								{
									bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
									bexp = bexp->mRight;
									bexp->mLeft = iexp;
									bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
									bexp = bexp->mRight;
									bexp->mLeft = bodyExp;
								}
								bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
								bexp = bexp->mRight;
								bexp->mLeft = dexp;

								if (conditionExp->mType == EX_RELATIONAL)
								{
									conditionExp->mRight->mDecValue = conditionExp->mRight->mDecValue->Clone();
								}
								else
								{
									conditionExp = new Expression(conditionExp->mLocation, EX_RELATIONAL);
									conditionExp->mDecType = TheBoolTypeDeclaration;
									conditionExp->mToken = stepValue < 0 ? TK_GREATER_THAN : TK_LESS_THAN;
									conditionExp->mLeft = initExp->mLeft;
									conditionExp->mRight = new Expression(conditionExp->mLocation, EX_CONSTANT);
									conditionExp->mRight->mDecType = conditionExp->mDecType;
									conditionExp->mRight->mDecValue = new Declaration(conditionExp->mLocation, DT_CONST_INTEGER);
									conditionExp->mRight->mDecValue->mBase = conditionExp->mRight->mDecType;
								}

								conditionExp->mRight->mDecValue->mInteger = numIterations;

								if (remain)
								{
									finalExp = new Expression(mScanner->mLocation, EX_SEQUENCE);
									finalExp->mLeft = bodyExp;
									Expression* bexp = finalExp;

									for (int i = 1; i < remain; i++)
									{
										bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
										bexp = bexp->mRight;
										bexp->mLeft = iexp;
										bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
										bexp = bexp->mRight;
										bexp->mLeft = bodyExp;
									}
								}

								bodyExp = unrollBody;
							}
							else
							{
								int	numSteps = stepValue > 0 ? (endValue - startValue + stepValue - 1) / stepValue : (endValue - startValue + stepValue + 1) / stepValue;
								int	remain = numSteps % unrollLoop;
								endValue -= remain * stepValue;

								if (conditionExp->mType == EX_RELATIONAL)
								{
									conditionExp->mRight->mDecValue = conditionExp->mRight->mDecValue->Clone();
								}
								else
								{
									conditionExp = new Expression(conditionExp->mLocation, EX_RELATIONAL);
									conditionExp->mDecType = TheBoolTypeDeclaration;
									conditionExp->mToken = stepValue < 0 ? TK_GREATER_THAN : TK_LESS_THAN;
									conditionExp->mLeft = initExp->mLeft;
									conditionExp->mRight = new Expression(conditionExp->mLocation, EX_CONSTANT);
									conditionExp->mRight->mDecType = conditionExp->mDecType;
									conditionExp->mRight->mDecValue = new Declaration(conditionExp->mLocation, DT_CONST_INTEGER);
									conditionExp->mRight->mDecValue->mBase = conditionExp->mRight->mDecType;
								}
								conditionExp->mRight->mDecValue->mInteger = endValue;

								Expression* unrollBody = new Expression(mScanner->mLocation, EX_FORBODY);
								unrollBody->mLeft = bodyExp;
								Expression* bexp = unrollBody;
								if ((endValue - startValue) * stepValue > 0)
								{
									for (int i = 1; i < unrollLoop; i++)
									{
										bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
										bexp = bexp->mRight;
										bexp->mLeft = iterateExp;
										bexp->mRight = new Expression(mScanner->mLocation, EX_FORBODY);
										bexp = bexp->mRight;
										bexp->mLeft = bodyExp;
									}

									conditionExp->mRight->mDecValue->mInteger = endValue - stepValue * (unrollLoop - 1);
								}

								if (remain)
								{
									finalExp = new Expression(mScanner->mLocation, EX_DO);
									finalExp->mLeft = new Expression(mScanner->mLocation, EX_CONSTANT);
									finalExp->mLeft->mDecType = TheBoolTypeDeclaration;
									finalExp->mLeft->mDecValue = TheFalseConstDeclaration;

									finalExp->mRight = new Expression(mScanner->mLocation, EX_FORBODY);
									finalExp->mRight->mLeft = bodyExp;
									Expression* bexp = finalExp->mRight;

									for (int i = 1; i < remain; i++)
									{
										bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
										bexp = bexp->mRight;
										bexp->mLeft = iterateExp;
										bexp->mRight = new Expression(mScanner->mLocation, EX_FORBODY);
										bexp = bexp->mRight;
										bexp->mLeft = bodyExp;
									}
								}

								bodyExp = unrollBody;
							}
						}
						else
							mErrors->Error(exp->mLocation, EWARN_LOOP_UNROLL_IGNORED, "Loop unroll ignored, bounds and step not integer");
					}
					else
						mErrors->Error(exp->mLocation, EWARN_LOOP_UNROLL_IGNORED, "Loop unroll ignored, bounds and step not const");
				}

				exp->mLeft->mRight = initExp;
				exp->mLeft->mLeft->mLeft = conditionExp;
				exp->mLeft->mLeft->mRight = iterateExp;
				exp->mRight = bodyExp;

				if (finalExp)
				{
					Expression* nexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
					nexp->mLeft = exp;
					nexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
					nexp->mRight->mLeft = finalExp;
					exp = nexp;
				}

				mScope = mScope->mParent;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'(' expected");
			break;
		case TK_SWITCH:
			mScanner->NextToken();
			exp = ParseSwitchStatement();
			break;
		case TK_RETURN:
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_RETURN);
			if (mScanner->mToken != TK_SEMICOLON)
			{
				exp->mLeft = ParseRExpression();
				if (mFunctionType && mFunctionType->mBase)
				{
					if (mFunctionType->mBase->mType == DT_TYPE_AUTO || mFunctionType->mBase->IsReference() && mFunctionType->mBase->mBase->mType == DT_TYPE_AUTO)
					{
						mFunctionType->mBase = mFunctionType->mBase->DeduceAuto(exp->mLeft->mDecType);

						if (mFunctionType->mBase->IsComplexStruct())
						{
							// Make room for value struct return
							Declaration* p = mFunctionType->mParams;
							while (p)
							{
								p->mVarIndex += 2;
								p = p->mNext;
							}
						}
					}
					exp->mLeft = CoerceExpression(exp->mLeft, mFunctionType->mBase);
				}
				exp->mLeft = CleanupExpression(exp->mLeft);
				if (exp->mLeft->mType == EX_CONSTRUCT && mFunctionType && mFunctionType->mBase && mFunctionType->mBase->IsComplexStruct())
				{
					Expression* cexp = exp->mLeft->mLeft->mLeft;

					exp->mLeft->mLeft->mRight = nullptr;

					exp->mLeft->mRight->mType = EX_RESULT;
				}
			}
			ConsumeToken(TK_SEMICOLON);
			break;
		case TK_BREAK:
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_BREAK);
			ConsumeToken(TK_SEMICOLON);
			break;
		case TK_CONTINUE:
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_CONTINUE);
			ConsumeToken(TK_SEMICOLON);
			break;
		case TK_SEMICOLON:
			exp = new Expression(mScanner->mLocation, EX_VOID);
			mScanner->NextToken();
			break;
		case TK_ASM:
		{
			mScanner->NextToken();

			uint64	aflags = ParseAssemblerFlags();

			if (mScanner->mToken == TK_OPEN_BRACE)
			{
				mScanner->NextToken();
				exp = ParseAssembler();
				exp->mDecValue->mFlags |= aflags;

				if (mScanner->mToken == TK_CLOSE_BRACE)
					mScanner->NextToken();
				else
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");
			}
			else
			{
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");
				exp = new Expression(mScanner->mLocation, EX_VOID);
			}
		}	break;
		case TK_ASSUME:
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_ASSUME);
			exp->mLeft = ParseParenthesisExpression();
			ConsumeToken(TK_SEMICOLON);
			break;
		case TK_STATIC_ASSERT:
			mScanner->NextToken();
			ParseStaticAssert();
			break;
		case TK_GOTO:
#if 1
			exp = new Expression(mScanner->mLocation, EX_GOTO);
			mScanner->NextToken();
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dl = new Declaration(mScanner->mLocation, DT_CLABEL);
				dl->mIdent = mScanner->mTokenIdent;
				exp->mDecValue = dl;
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
#else
			mErrors->Error(mScanner->mLocation, EERR_UNIMPLEMENTED, "'goto' not implemented");
			mScanner->NextToken();
			exp = new Expression(mScanner->mLocation, EX_VOID);
#endif
			break;

		default:
			exp = CleanupExpression(ParseListExpression(true));
			if (exp->mType != EX_LABEL)
				ConsumeToken(TK_SEMICOLON);
			break;
		}
	}

	assert(exp);

	return exp;
}

Expression* Parser::ParseSwitchStatement(void)
{
	Expression* sexp = new Expression(mScanner->mLocation, EX_SWITCH);

	if (mScanner->mToken == TK_OPEN_PARENTHESIS)
	{
		mScanner->NextToken();
		sexp->mLeft = CleanupExpression(ParseExpression(true));
		if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
			mScanner->NextToken();
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected");
	}
	else
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'(' expected");

	if (mScanner->mToken == TK_OPEN_BRACE)
	{
		mScanner->NextToken();

		if (mScanner->mToken != TK_CLOSE_BRACE)
		{
			Expression* pcsexp = nullptr;

			Expression* cexp = nullptr;

			Expression* pexp = nullptr;
			do
			{
				if (mScanner->mToken == TK_CASE)
				{
					mScanner->NextToken();
					cexp = new Expression(mScanner->mLocation, EX_CASE);
					pexp = cexp;
					cexp->mLeft = ParseRExpression();

					if (ConsumeTokenIf(TK_ELLIPSIS))
					{
						Expression* rexp = new Expression(mScanner->mLocation, EX_LIST);
						rexp->mLeft = cexp->mLeft;
						rexp->mRight = ParseRExpression();
						cexp->mLeft = rexp;
					}

					if (mScanner->mToken == TK_COLON)
						mScanner->NextToken();
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "':' expected");

					Expression* csexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
					csexp->mLeft = cexp;
					if (pcsexp)
						pcsexp->mRight = csexp;
					else
						sexp->mRight = csexp;
					pcsexp = csexp;

				}
				else if (mScanner->mToken == TK_DEFAULT)
				{
					mScanner->NextToken();
					cexp = new Expression(mScanner->mLocation, EX_DEFAULT);
					pexp = cexp;

					if (mScanner->mToken == TK_COLON)
						mScanner->NextToken();
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "':' expected");

					Expression * csexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
					csexp->mLeft = cexp;					
					if (pcsexp)
						pcsexp->mRight = csexp;
					else
						sexp->mRight = csexp;
					pcsexp = csexp;					
				}
				else
				{
					Expression* nexp = ParseStatement();
					if (cexp)
					{
						Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
						sexp->mLeft = nexp;
						pexp->mRight = sexp;
						pexp = sexp;
					}
				}

			} while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF);
		}

		if (mScanner->mToken == TK_CLOSE_BRACE)
			mScanner->NextToken();
		else
			mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");
	}
	else
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'{' expected");

	return sexp;
}

int Parser::ExpansionDistance(Declaration* tdec, Declaration* spec, Declaration* xtdec)
{
	Declaration* ptdec = tdec->mParams;
	Declaration* psdec = spec->mParams;

	int cost = 0;
	if (tdec->mParser)
		cost = 100000;

	while (ptdec && psdec)
	{
		if (ptdec->mType == DT_CONST_TEMPLATE && psdec->mType == DT_CONST_TEMPLATE)
		{
			if (ptdec->mBase)
			{
				if (ptdec->mBase->mType == DT_CONST_INTEGER)
				{
					if (ptdec->mBase->mInteger != psdec->mBase->mInteger)
						return NOOVERLOAD;
				}
				else if (ptdec->mBase->mType == DT_CONST_TEMPLATE)
				{
					Declaration* pdec = xtdec->mScope->Insert(ptdec->mBase->mIdent, psdec->mBase);
					cost += 100;
				}
			}
			else
			{
				Declaration* pdec = xtdec->mScope->Insert(ptdec->mIdent, psdec->mBase);
				cost += 100;
			}
		}
		else if (ptdec->mType == DT_TYPE_TEMPLATE && psdec->mType == DT_TYPE_TEMPLATE)
		{
			if (ptdec->mBase)
			{
				if (!xtdec->ResolveTemplate(psdec->mBase, ptdec->mBase, true, false))
					return NOOVERLOAD;
			}
			else if (!xtdec->ResolveTemplate(psdec->mBase, ptdec, true, false))
				return NOOVERLOAD;
			else
				cost += 100;
		}
		else if (ptdec->mType == DT_PACK_TEMPLATE && psdec->mType == DT_PACK_TEMPLATE)
		{
			if (ptdec->mBase)
			{
				
				Declaration* tvp = ptdec->mBase->mParams;
				Declaration* svp = psdec->mBase->mParams;

				while (tvp && svp && tvp->IsSame(svp))
				{
					tvp = tvp->mNext;
					svp = svp->mNext;
				}

				if (tvp || svp)
					return NOOVERLOAD;
			}
			else if (psdec->mBase)
			{
				if (!xtdec->ResolveTemplate(psdec->mBase, ptdec, true, false))
					return NOOVERLOAD;

				Declaration* dec = psdec->mBase->mParams;
				while (dec)
				{
					cost += 200;
					dec = dec->mNext;
				}
			}
		}
		else if (ptdec->mType == DT_PACK_TEMPLATE)
		{
			if (ptdec->mBase)
			{
				ptdec = ptdec->mBase->mParams;
				continue;
			}
			else if (psdec->mBase)
			{
				if (!xtdec->ResolveTemplate(psdec->mBase, ptdec, true, false))
					return NOOVERLOAD;
				psdec = psdec->mNext;
				cost += 200;
				continue;
			}
			else
			{
				while (psdec)
				{
					cost += 200;
					psdec = psdec->mNext;
				}

				return cost;
			}
		}
		else
			return NOOVERLOAD;

		ptdec = ptdec->mNext;
		psdec = psdec->mNext;
	}

	if (ptdec && ptdec->mType == DT_PACK_TEMPLATE)
	{
		if (ptdec->mBase)
		{
			if (ptdec->mBase->mParams)
				return NOOVERLOAD;
		}
		else
			cost += 50;
	}
	else if (ptdec || psdec)
		return NOOVERLOAD;

	return cost;
}

void Parser::ParseTemplateArguments(Declaration* tmpld, Declaration* tdec)
{
	ConsumeToken(TK_LESS_THAN);

	Declaration* ppdec = nullptr;

	if (!ConsumeTokenIf(TK_GREATER_THAN))
	{
		Declaration* tparm = tmpld->mParams;
		while (tmpld->mNext && !tparm)
		{
			tmpld = tmpld->mNext;
			tparm = tmpld->mParams;
		}

		do
		{
			Expression* exp;
			
			if (tparm && tparm->mType == DT_TYPE_TEMPLATE)
				exp = ParseSimpleExpression(false, true);
			else
				exp = ParseShiftExpression(false);

			Declaration* pdec = nullptr;

			if (exp->mType == EX_TYPE)
			{
				pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE);
				pdec->mBase = exp->mDecType;
			}
			else if (exp->mType == EX_PACK_TYPE)
			{
				ConsumeToken(TK_ELLIPSIS);

				if (exp->mDecType->mType == DT_PACK_TYPE)
				{
					Declaration* ptdec = exp->mDecType->mParams;
					while (ptdec)
					{
						pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE);
						pdec->mBase = ptdec;

						if (pdec)
						{
							if (ppdec)
								ppdec->mNext = pdec;
							else
								tdec->mParams = pdec;
							ppdec = pdec;
						}

						ptdec = ptdec->mNext;
					}
					continue;
				}
				else
				{
					pdec = new Declaration(exp->mLocation, DT_PACK_TEMPLATE);
					pdec->mBase = exp->mDecType;
				}
			}
			else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION)
			{
				pdec = new Declaration(exp->mLocation, DT_TYPE_TEMPLATE);
				pdec->mBase = exp->mDecValue;
			}
			else if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_TEMPLATE))
			{
				pdec = new Declaration(exp->mLocation, DT_CONST_TEMPLATE);
				pdec->mBase = exp->mDecValue;
			}
			else
				mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Template specification expected");

			if (pdec)
			{
				if (ppdec)
					ppdec->mNext = pdec;
				else
					tdec->mParams = pdec;
				ppdec = pdec;
			}

			if (tparm)
				tparm = tparm->mNext;

		} while (ConsumeTokenIf(TK_COMMA));

		ConsumeToken(TK_GREATER_THAN);
	}
}

Declaration* Parser::ParseTemplateExpansion(Declaration* tmpld, Declaration* expd)
{
	Declaration	* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
	tdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);

#if 1
	if (expd)
	{
		if (tmpld->mBase->mType == DT_TEMPLATE)
		{
			Parser* p = tmpld->mBase->mParser->Clone();
			p->mParent = this;

			p->mScanner->Replay(tmpld->mBase->mTokens);

			tdec = tmpld->mBase->Clone();
			tdec->mScope = tdec->mScope->Clone();
			tdec->mScope->mName = expd->mScope->mName;
			tdec->mScope->mParent = expd->mScope;

			p->ParseTemplateDeclarationBody(tdec, nullptr);

			return tdec;
		}

		Declaration* ppdec = nullptr;
		Declaration* dec = expd->mParams;

		while (dec)
		{
			Declaration* epdec = dec->Clone();

			if (ppdec)
				ppdec->mNext = epdec;
			else
				tdec->mParams = epdec;
			ppdec = epdec;

			dec = dec->mNext;
		}
	}
	else
	{
		ParseTemplateArguments(tmpld, tdec);
	}

	Declaration* tmplpd = tmpld;
	while (!tmpld->mTokens)
		tmpld = tmpld->mNext;

	Declaration* epdec = tdec->mParams;
	while (epdec && epdec->mBase && epdec->mBase->mType != DT_TYPE_TEMPLATE && epdec->mBase->mType != DT_CONST_TEMPLATE && epdec->mBase->mType != DT_PACK_TEMPLATE)
		epdec = epdec->mNext;

	if (epdec)
	{
		// Partial template specification
		Declaration* bdec = new Declaration(mScanner->mLocation, tmpld->mBase->mType);
		tdec->mBase = bdec;
		bdec->mTemplate = tdec;
		bdec->mBase = tmpld->mBase->mBase;
		tdec->mIdent = tmpld->mIdent;
		tdec->mQualIdent = tmpld->mQualIdent;
		tdec->mScope->mName = tdec->mIdent;
		tdec->mNext = tmpld;
		bdec->mIdent = tdec->mIdent->Mangle(tdec->MangleIdent()->mString);

		return bdec;
	}

	Declaration* pthis = tmpld->mClass;

	int	mindist = NOOVERLOAD;
	Declaration* etdec = nullptr;

	Declaration* dec = tmpld;
	Declaration* mxtdec = nullptr;
	while (dec)
	{
		Declaration* xtdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
		xtdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);

		int dist = ExpansionDistance(dec, tdec, xtdec);
		if (dist < mindist)
		{
			mxtdec = xtdec;
			mindist = dist;
			etdec = dec;
		}
		dec = dec->mNext;
	}

	if (mindist == 0)
		return etdec->mBase;
	else if (mindist == NOOVERLOAD)
	{
		mErrors->Error(FullLocation(tmpld->mLocation), EERR_TEMPLATE_PARAMS, "No matching template parameters", tmpld->mQualIdent);
		return tdec;
	}
	else
		tmpld = etdec;

	dec = tdec->mParams;
	Declaration	*	pdec = tmpld->mBase->mTemplate->mParams;
	
	Declaration	*	ppdec = nullptr;
	while (pdec)
	{
		Declaration* rdec = mxtdec->mScope->Lookup(pdec->mIdent);
		if (pdec->mType == DT_PACK_TEMPLATE)
		{
			if (!rdec)
			{
				rdec = new Declaration(tdec->mLocation, DT_PACK_TYPE);
			}
			else if (!dec)
			{
				Declaration* packd = new Declaration(tdec->mLocation, DT_PACK_TEMPLATE);
				packd->mBase = new Declaration(tdec->mLocation, DT_PACK_TYPE);
				if (ppdec)
					ppdec->mNext = packd;
				else
					tdec->mParams = packd;

				ppdec = nullptr;
				dec = packd;
			}
			else if (dec->mType != DT_PACK_TEMPLATE)
			{
				Declaration* packd = new Declaration(dec->mLocation, DT_PACK_TEMPLATE);
				packd->mBase = new Declaration(dec->mLocation, DT_PACK_TYPE);
				if (ppdec)
					ppdec->mNext = packd;
				else if (tdec->mParams && !tdec->mParams->mNext && tdec->mParams->mType == DT_TYPE_TEMPLATE)
					;
				else
					tdec->mParams = packd;

				ppdec = nullptr;
				while (dec)
				{
					Declaration* ndec = dec->mBase->Clone();

					if (ppdec)
						ppdec->mNext = ndec;
					else
						packd->mBase->mParams = ndec;
					ppdec = ndec;
					dec = dec->mNext;
				}

				dec = packd;
			}
		}
		else
		{
			ppdec = dec;
			dec = dec->mNext;
		}

		if (rdec)
		{
//			rdec->mIdent = pdec->mIdent;
			tdec->mScope->Insert(pdec->mIdent, rdec);
		}

		pdec = pdec->mNext;
	}


#else
	if (expd)
	{
		if (tmpld->mBase->mType == DT_TEMPLATE)
		{
			Parser* p = tmpld->mBase->mParser->Clone();

			p->mScanner->Replay(tmpld->mBase->mTokens);

			tdec = tmpld->mBase->Clone();
			tdec->mScope->mName = expd->mScope->mName;
			tdec->mScope->mParent = expd->mScope;

			p->ParseTemplateDeclarationBody(tdec, nullptr);

			return tdec;
		}

		Declaration* ppdec = nullptr;
		Declaration* dec = expd->mParams;
		Declaration* pdec = tmpld->mParams;

		while (dec)
		{
			Declaration* epdec = dec->Clone();

			tdec->mScope->Insert(epdec->mIdent, epdec->mBase);
			epdec->mFlags |= DTF_DEFINED;

			if (ppdec)
				ppdec->mNext = epdec;
			else
				tdec->mParams = epdec;
			ppdec = epdec;

			dec = dec->mNext;
			pdec = pdec->mNext;
		}

		if (pdec)
		{
			if (ppdec)
				ppdec->mNext = pdec;
			else
				tdec->mParams = pdec;
		}

	}
	else
	{
		ConsumeToken(TK_LESS_THAN);

		Declaration* ppdec = nullptr;
		Declaration* pdec = tmpld->mParams;

		// Carry over already specialized parameters
		while (pdec && (pdec->mType != DT_TYPE_TEMPLATE && pdec->mType != DT_CONST_TEMPLATE))
		{
			Declaration* epdec = pdec->Clone();

			tdec->mScope->Insert(epdec->mIdent, epdec->mBase);
			epdec->mFlags |= DTF_DEFINED;

			if (ppdec)
				ppdec->mNext = epdec;
			else
				tdec->mParams = epdec;
			ppdec = epdec;

			pdec = pdec->mNext;
		}

		// Now to the new parameters
		while (pdec)
		{
			Declaration* epdec = pdec->Clone();
			Expression* exp = ParseShiftExpression(false);

			if (epdec->mType == DT_TYPE_TEMPLATE)
			{
				if (exp->mType == EX_TYPE)
					epdec->mBase = exp->mDecType;
				else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION)
					epdec->mBase = exp->mDecValue;
				else
				{
					mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Type parameter expected", pdec->mIdent);
					epdec->mBase = TheVoidTypeDeclaration;
				}
			}
			else if (epdec->mType == DT_CONST_TEMPLATE)
			{
				if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_TEMPLATE))
					epdec->mBase = exp->mDecValue;
				else
					mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Const integer parameter expected", pdec->mIdent);
			}

			tdec->mScope->Insert(epdec->mIdent, epdec->mBase);
			epdec->mFlags |= DTF_DEFINED;

			if (ppdec)
				ppdec->mNext = epdec;
			else
				tdec->mParams = epdec;
			ppdec = epdec;

			pdec = pdec->mNext;
			if (pdec && !ConsumeTokenIf(TK_COMMA))
				break;
		}

		ConsumeToken(TK_GREATER_THAN);

		// Partial template arguments given
		if (pdec)
		{
			if (ppdec)
				ppdec->mNext = pdec;
			else
				tdec->mParams = pdec;
		}
	}

	while (!tmpld->mTokens)
		tmpld = tmpld->mNext;

	Declaration* pthis = tmpld->mClass;

	Declaration* etdec = tmpld->mNext;
	while (etdec && !etdec->IsSameParams(tdec))
		etdec = etdec->mNext;
#endif

	Parser* p = tmpld->mParser->Clone();
	p->mParent = this;

	p->mScanner->Replay(tmpld->mTokens);

	tdec->mIdent = tmpld->mIdent;
	tdec->mScope->mName = tdec->MangleIdent();
	tdec->mNext = tmpld->mNext;
	tmpld->mNext = tdec;

	tdec->mScope->mParent = tmpld->mScope->mParent;

	p->mTemplateScope = tdec->mScope;
	if (tmpld->mFlags & DTF_AUTO_TEMPLATE)
	{
		Declaration	*	ndec = tmpld->mBase->ExpandTemplate(tdec->mScope);

		Declaration* pdec = tmpld->mBase;
			
		if (pdec)
		{
			Declaration* pcdec = nullptr;

			while (pdec && !ndec->mBase->IsSameParams(pdec->mBase))
			{
				pcdec = pdec;
				pdec = pdec->mNext;
			}

			if (!pdec)
				pcdec->mNext = ndec;
		}

		tdec->mBase = ndec;
		ndec->mValue = p->ParseFunction(ndec->mBase);
		ndec->mNumVars = mLocalIndex;
		ndec->mFlags |= DTF_DEFINED;

		ndec->mIdent = ndec->mIdent->Mangle(tdec->mScope->mName->mString);
		ndec->mQualIdent = ndec->mQualIdent->Mangle(tdec->mScope->mName->mString);
	}
	else
	{
		Declaration* tpthis = nullptr;
		if (tmpld->mClass)
			tpthis = tmpld->mClass;
		else if (expd && expd->mBase)
			tpthis = expd->mBase->BuildConstPointer(tdec->mLocation);
#if 0
		if (tpthis)
		{
			DeclarationScope* oscope = p->mScope;
			tpthis->mBase->mScope->mParent = p->mScope;
			p->mScope = tpthis->mBase->mScope;

			tdec->mBase = p->ParseDeclaration(nullptr, true, false, tpthis, tdec);

			p->mScope = oscope;
		}
		else
#endif
		tdec->mBase = p->ParseDeclaration(nullptr, true, false, false, tpthis, tdec);
	}

	p->mTemplateScope = nullptr;

	if (tdec->mBase->mType == DT_ANON)
	{
		tdec->mBase = tdec->mBase->mBase;
		mCompilationUnits->mTemplateScope->Insert(tmpld->mQualIdent, tmpld);

		tdec->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
			{
				if (mdec->mType == DT_CONST_FUNCTION)
				{
					while (mdec)
					{
						if (!(mdec->mFlags & DTF_DEFINED))
						{
							Declaration* mpdec = mCompilationUnits->mScope->Lookup(tmpld->mScope->Mangle(mdec->mIdent));
							while (mpdec && !mdec->mBase->IsTemplateSameParams(mpdec->mBase, tdec))
								mpdec = mpdec->mNext;
							if (mpdec && mpdec->mTemplate)
							{
								Declaration* rdec;
								if (mdec->mTemplate)
								{
									Declaration	*	mtdec = p->ParseTemplateExpansion(mpdec->mTemplate, tdec);
									mtdec->mClass = mdec->mTemplate->mClass;
									mdec->mTemplate = mtdec;
									mdec->mTemplate->mBase = mdec;
									rdec = mtdec;
								}
								else
									rdec = p->ParseTemplateExpansion(mpdec->mTemplate, tdec);
								if (mdec->mBase->mBase->IsAuto())
									mdec->mBase->mBase = rdec->mBase->mBase;
							}
						}

						mdec = mdec->mNext;
					}
				}
			});
	}

	return tdec->mBase;
}

void Parser::CompleteTemplateExpansion(Declaration* tmpld)
{
	tmpld = tmpld->mNext;
	while (tmpld)
	{
		if (tmpld->mBase->mType == DT_TYPE_STRUCT)
		{
			// now expand the templated members

			tmpld->mBase->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
				{
					if (mdec->mType == DT_CONST_FUNCTION)
					{
						while (mdec)
						{
							Declaration* mpdec = mCompilationUnits->mScope->Lookup(mdec->mQualIdent);
							while (mpdec && !mpdec->IsSameParams(mdec->mParams))
								mpdec = mpdec->mNext;
							if (mpdec && mpdec->mType == DT_TEMPLATE)
							{
								ParseTemplateExpansion(mpdec, tmpld);
							}

							mdec = mdec->mNext;
						}
					}
				});
		}
	}
}


Declaration* Parser::FunctionAutoParamsToTemplate(Declaration* fdec)
{
	Declaration* pdec = fdec->mBase->mParams;
	while (pdec && !pdec->mBase->IsAuto())
		pdec = pdec->mNext;

	if (pdec)
	{
		Declaration* tdec = new Declaration(fdec->mLocation, DT_TEMPLATE);
		tdec->mParser = this->Clone();
		tdec->mScope = new DeclarationScope(mTemplateScope, SLEVEL_TEMPLATE);
		Declaration* ppdec = nullptr;

		int	ntp = 0;
		pdec = fdec->mBase->mParams;
		while (pdec)
		{
			Declaration* ptdec = nullptr;

			if (pdec->mBase->mType == DT_TYPE_AUTO)
			{
				ptdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE);
				pdec->mBase = ptdec;
			}
			else if (pdec->mBase->IsReference() && pdec->mBase->mBase->mType == DT_TYPE_AUTO)
			{
				ptdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE);
				pdec->mBase->mBase = ptdec;
			}

			if (ptdec)
			{
				ptdec->mIdent = Ident::Unique("T", ntp++);
				tdec->mScope->Insert(ptdec->mIdent, ptdec);
				ptdec->mFlags |= DTF_DEFINED;

				if (ppdec)
					ppdec->mNext = ptdec;
				else
					tdec->mParams = ptdec;
				ppdec = ptdec;
			}

			pdec = pdec->mNext;
		}

		fdec->mCompilerOptions = mCompilerOptions;
		fdec->mBase->mCompilerOptions = mCompilerOptions;

		tdec->mBase = fdec;
		fdec->mTemplate = tdec;

		mScanner->BeginRecord();

		if (ConsumeTokenIf(TK_OPEN_BRACE))
		{
			int	qdepth = 1;
			while (qdepth)
			{
				if (ConsumeTokenIf(TK_OPEN_BRACE))
					qdepth++;
				else if (ConsumeTokenIf(TK_CLOSE_BRACE))
					qdepth--;
				else
					mScanner->NextToken();
			}
		}

		tdec->mTokens = mScanner->CompleteRecord();

		tdec->mIdent = tdec->mBase->mIdent;
		tdec->mQualIdent = tdec->mBase->mQualIdent;
		tdec->mScope->mName = tdec->mQualIdent;
		tdec->mFlags |= DTF_AUTO_TEMPLATE;

		if (tdec->mQualIdent == mScope->Mangle(tdec->mIdent))
			mScope->Insert(tdec->mIdent, tdec->mBase);

		Declaration* pdec = mCompilationUnits->mScope->Insert(tdec->mQualIdent, tdec->mBase);
		if (pdec)
		{
			Declaration* ppdec = pdec;
			while (pdec && !pdec->IsSameTemplate(tdec->mBase))
			{
				ppdec = pdec;
				pdec = pdec->mNext;
			}

			if (!pdec)
			{
				ppdec->mNext = tdec->mBase;
				tdec->mBase->mNext = nullptr;
			}
		}

		return fdec;
	}
	else
		return nullptr;
}

Declaration * Parser::ParseTemplateDeclaration(Declaration* pthis)
{
	Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
	tdec->mParser = this->Clone();
	tdec->mScope = new DeclarationScope(mTemplateScope, SLEVEL_TEMPLATE);
	tdec->mClass = pthis;
	Declaration* ppdec = nullptr;

	ConsumeToken(TK_LESS_THAN);
	if (mScanner->mToken != TK_GREATER_THAN)
	{
		for (;;)
		{
			Declaration* pdec = nullptr;

			if (ConsumeTokenIf(TK_CLASS) || ConsumeTokenIf(TK_TYPENAME))
			{
				if (ConsumeTokenIf(TK_ELLIPSIS))
				{
					if (mScanner->mToken == TK_IDENT)
					{
						pdec = new Declaration(mScanner->mLocation, DT_PACK_TEMPLATE);
						pdec->mIdent = mScanner->mTokenIdent;
						mScanner->NextToken();
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
				}
				else if (mScanner->mToken == TK_IDENT)
				{
					pdec = new Declaration(mScanner->mLocation, DT_TYPE_TEMPLATE);
					pdec->mIdent = mScanner->mTokenIdent;
					mScanner->NextToken();
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
			}
			else if (ConsumeTokenIf(TK_INT))
			{
				if (mScanner->mToken == TK_IDENT)
				{
					pdec = new Declaration(mScanner->mLocation, DT_CONST_TEMPLATE);
					pdec->mIdent = mScanner->mTokenIdent;
					mScanner->NextToken();
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_TEMPLATE_PARAMS, "'class' or 'int' expected as template parameter");

			if (pdec)
			{
				tdec->mScope->Insert(pdec->mIdent, pdec);
				pdec->mFlags |= DTF_DEFINED;

				if (ppdec)
					ppdec->mNext = pdec;
				else
					tdec->mParams = pdec;
				ppdec = pdec;
			}

			if (!ConsumeTokenIf(TK_COMMA))
				break;
		}
	}

	ConsumeToken(TK_GREATER_THAN);

	if (ConsumeTokenIf(TK_TEMPLATE))
	{
		mTemplateScope = tdec->mScope;
		tdec->mBase = ParseTemplateDeclaration(pthis);
		mTemplateScope = tdec->mScope->mParent;
		tdec->mBase->mBase->mTemplate = tdec;
	}
	else
		ParseTemplateDeclarationBody(tdec, pthis);

	return tdec;
}

void Parser::ParseTemplateDeclarationBody(Declaration * tdec, Declaration * pthis)
{
	mScanner->BeginRecord();
	if (mScanner->mToken == TK_CLASS || mScanner->mToken == TK_STRUCT)
	{
		// Class template
		Declaration* bdec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT);
		tdec->mBase = bdec;
		bdec->mTemplate = tdec;

		mScanner->NextToken();
		if (mScanner->mToken == TK_IDENT)
		{
			bdec->mIdent = mScanner->mTokenIdent;
			bdec->mQualIdent = mScope->Mangle(mScanner->mTokenIdent);
			bdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS, bdec->mQualIdent);

			mScanner->NextToken();
			if (mScanner->mToken == TK_LESS_THAN)
			{
				Declaration* ptdec = new Declaration(mScanner->mLocation, DT_TEMPLATE);
				ptdec->mScope = new DeclarationScope(nullptr, SLEVEL_TEMPLATE);

				mTemplateScope = tdec->mScope;
				ParseTemplateArguments(tdec, ptdec);

				ptdec->mBase = bdec;
				ptdec->mParser = tdec->mParser;
				tdec = ptdec;
			}

			while (mScanner->mToken != TK_SEMICOLON && mScanner->mToken != TK_OPEN_BRACE)
				mScanner->NextToken();
			
			if (ConsumeTokenIf(TK_OPEN_BRACE))
			{
				int	qdepth = 1;
				while (qdepth)
				{
					if (ConsumeTokenIf(TK_OPEN_BRACE))
						qdepth++;
					else if (ConsumeTokenIf(TK_CLOSE_BRACE))
						qdepth--;
					else
						mScanner->NextToken();
				}
			}
		}			
		else
			mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Class template expected");
	}
	else
	{
		// Function template
		mTemplateScope = tdec->mScope;

		ConsumeTokenIf(TK_INLINE);
		ConsumeTokenIf(TK_NOINLINE);
		ConsumeTokenIf(TK_FORCEINLINE);
		ConsumeTokenIf(TK_CONSTEXPR);

		Declaration* bdec = ParseBaseTypeDeclaration(0, true);
		Declaration* adec = nullptr;

		if (ConsumeTokenIf(TK_COLCOLON))
		{
			if (mScanner->mToken == TK_IDENT && mScanner->mTokenIdent == bdec->mTemplate->mIdent)
			{
				mScanner->NextToken();

				Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

				adec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);

				adec->mBase = ctdec;
				adec->mIdent = bdec->mTemplate->mIdent->PreMangle("+");

				char	buffer[200];
				strcpy_s(buffer, bdec->mTemplate->mQualIdent->mString);
				strcat_s(buffer, "::");
				strcat_s(buffer, adec->mIdent->mString);
				adec->mQualIdent = Ident::Unique(buffer);
			}
			else if (ConsumeToken(TK_BINARY_NOT) && mScanner->mToken == TK_IDENT && mScanner->mTokenIdent == bdec->mTemplate->mIdent)
			{
				mScanner->NextToken();

				Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

				adec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);

				adec->mBase = ctdec;
				adec->mIdent = bdec->mTemplate->mIdent->PreMangle("~");

				char	buffer[200];
				strcpy_s(buffer, bdec->mTemplate->mQualIdent->mString);
				strcat_s(buffer, "::");
				strcat_s(buffer, adec->mIdent->mString);
				adec->mQualIdent = Ident::Unique(buffer);
			}
			else
				mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Constructor or destructor expected");
		}
		else
		{
			if (bdec && pthis && bdec == pthis->mBase && mScanner->mToken == TK_OPEN_PARENTHESIS)
			{
				Declaration* ctdec = ParseFunctionDeclaration(TheVoidTypeDeclaration);

				adec = new Declaration(ctdec->mLocation, DT_CONST_FUNCTION);

				adec->mBase = ctdec;
				adec->mIdent = pthis->mBase->mIdent->PreMangle("+");
				adec->mQualIdent = pthis->mBase->mScope->Mangle(adec->mIdent);

				if (ConsumeTokenIf(TK_COLON))
				{
					do {
						ConsumeToken(TK_IDENT);
						if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
						{
							while (mScanner->mToken != TK_OPEN_PARENTHESIS)
								mScanner->NextToken();
							mScanner->NextToken();
						}
						else if (ConsumeTokenIf(TK_OPEN_BRACE))
						{
							int	qdepth = 1;
							while (qdepth)
							{
								if (ConsumeTokenIf(TK_OPEN_BRACE))
									qdepth++;
								else if (ConsumeTokenIf(TK_CLOSE_BRACE))
									qdepth--;
								else
									mScanner->NextToken();
							}
						}

					} while (ConsumeTokenIf(TK_COMMA));
				}

			}
			else
			{
				adec = ParsePostfixDeclaration();
				adec = ReverseDeclaration(adec, bdec);
			}
		}

		mTemplateScope = tdec->mScope->mParent;

		if (adec->mBase->mType == DT_TYPE_FUNCTION)
		{
			if (pthis)
				PrependThisArgument(adec->mBase, pthis);

			if (ConsumeTokenIf(TK_CONST))
				adec->mBase->mFlags |= DTF_CONST;

			adec->mType = DT_CONST_FUNCTION;
			adec->mSection = mCodeSection;

			if (mCompilerOptions & COPT_NATIVE)
				adec->mFlags |= DTF_NATIVE;

			tdec->mBase = adec;
			adec->mTemplate = tdec;

			if (ConsumeTokenIf(TK_COLON))
			{
				if (adec->mIdent->mString[0] != '+')
					mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template body for non constructor expected");

				do {
					ConsumeToken(TK_IDENT);
					if (ConsumeToken(TK_OPEN_PARENTHESIS))
					{
						int	qdepth = 1;
						while (qdepth)
						{
							if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
								qdepth++;
							else if (ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
								qdepth--;
							else
								mScanner->NextToken();
						}
					}
				} while (ConsumeTokenIf(TK_COMMA));
			}

			if (ConsumeTokenIf(TK_OPEN_BRACE))
			{
				int	qdepth = 1;
				while (qdepth)
				{
					if (ConsumeTokenIf(TK_OPEN_BRACE))
						qdepth++;
					else if (ConsumeTokenIf(TK_CLOSE_BRACE))
						qdepth--;
					else
						mScanner->NextToken();
				}
			}
			else if (ConsumeTokenIf(TK_SEMICOLON))
			{
				
			}
			else
			{
				mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template body expected");
				adec->mType = DT_TYPE_VOID;
				tdec->mBase = adec;
				adec->mIdent = adec->mQualIdent = Ident::Unique("_");
				adec->mTemplate = tdec;
			}
		}
		else
		{
			mErrors->Error(bdec->mLocation, EERR_FUNCTION_TEMPLATE, "Function template expected");
			adec->mType = DT_TYPE_VOID;
			tdec->mBase = adec;
			adec->mIdent = adec->mQualIdent = Ident::Unique("_");
			adec->mTemplate = tdec;
		}
	}

	tdec->mTokens = mScanner->CompleteRecord();

	tdec->mIdent = tdec->mBase->mIdent;
	tdec->mQualIdent = tdec->mBase->mQualIdent;
	tdec->mScope->mName = tdec->mQualIdent;

	if (tdec->mQualIdent == mScope->Mangle(tdec->mIdent))
	{
		Declaration* pdec = mScope->Insert(tdec->mIdent, tdec->mBase);
		if (pdec)
		{
			Declaration* ppdec = pdec;
			while (pdec && !pdec->IsSameTemplate(tdec->mBase))
			{
				ppdec = pdec;
				pdec = pdec->mNext;
			}

			if (!pdec)
			{
				ppdec->mNext = tdec->mBase;
				tdec->mBase->mNext = nullptr;
			}
			else if (pdec->mTemplate)
			{
				tdec->mNext = pdec->mTemplate->mNext;
				pdec->mTemplate->mNext = tdec;
			}
		}
	}
	
	Declaration* pdec = mCompilationUnits->mScope->Insert(tdec->mQualIdent, tdec->mBase);
	if (pdec)
	{
		Declaration* ppdec = pdec;
		while (pdec && !pdec->IsSameTemplate(tdec->mBase))
		{
			ppdec = pdec;
			pdec = pdec->mNext;
		}

		if (!pdec)
		{
			ppdec->mNext = tdec->mBase;
			tdec->mBase->mNext = nullptr;
		}
	}
}


Expression* Parser::ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = nullptr;
	Declaration* dec;

	switch (mScanner->mToken)
	{
	case TK_SUB:
		mScanner->NextToken();
		exp = ParseAssemblerBaseOperand(pcasm, pcoffset);
		if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
		{
			dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
			dec->mInteger = - exp->mDecValue->mInteger;
			if (dec->mInteger < 32768)
				dec->mBase = TheSignedIntTypeDeclaration;
			else
				dec->mBase = TheUnsignedIntTypeDeclaration;
			exp = new Expression(mScanner->mLocation, EX_CONSTANT);
			exp->mDecValue = dec;
			exp->mDecType = dec->mBase;
		}
		else
			mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Cannot negate expression");
		break;

	case TK_BINARY_NOT:
		mScanner->NextToken();
		exp = ParseAssemblerBaseOperand(pcasm, pcoffset);
		if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
		{
			dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
			dec->mInteger = ~exp->mDecValue->mInteger;
			dec->mBase = TheUnsignedIntTypeDeclaration;
			exp = new Expression(mScanner->mLocation, EX_CONSTANT);
			exp->mDecValue = dec;
			exp->mDecType = dec->mBase;
		}
		else
			mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Cannot negate expression");
		break;

	case TK_MUL:
		mScanner->NextToken();
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		dec = new Declaration(mScanner->mLocation, DT_LABEL);
		exp->mDecType = TheUnsignedIntTypeDeclaration;
		exp->mDecValue = dec;
		dec->mInteger = pcoffset;
		dec->mBase = pcasm;
		break;

	case TK_INTEGER:
	case TK_INTEGERL:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		if (dec->mInteger < 32768)
			dec->mBase = TheSignedIntTypeDeclaration;
		else
			dec->mBase = TheUnsignedIntTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_INTEGERU:
	case TK_INTEGERUL:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mScanner->mTokenInteger;
		dec->mBase = TheUnsignedIntTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;
	case TK_CHARACTER:
		dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
		dec->mInteger = mCharMap[(unsigned char)mScanner->mTokenInteger];
		dec->mBase = TheUnsignedCharTypeDeclaration;
		exp = new Expression(mScanner->mLocation, EX_CONSTANT);
		exp->mDecValue = dec;
		exp->mDecType = dec->mBase;

		mScanner->NextToken();
		break;

	case TK_OPEN_BRACKET:
		mScanner->NextToken();
		exp = ParseAssemblerOperand(pcasm, pcoffset);
		ConsumeToken(TK_CLOSE_BRACKET);
		break;

	case TK_OPEN_PARENTHESIS:
		mScanner->NextToken();
		exp = ParseAssemblerOperand(pcasm, pcoffset);
		ConsumeToken(TK_CLOSE_PARENTHESIS);
		break;

	case TK_IDENT:
		dec = mScope->Lookup(mScanner->mTokenIdent);
		if (!dec)
		{ 
			exp = new Expression(mScanner->mLocation, EX_CONSTANT);
			dec = new Declaration(mScanner->mLocation, DT_LABEL);
			dec->mIdent = mScanner->mTokenIdent;
			dec->mQualIdent = mScanner->mTokenIdent;
			exp->mDecType = TheUnsignedIntTypeDeclaration;
			mScope->Insert(dec->mIdent, dec);
		}
		else
		{
			exp = new Expression(mScanner->mLocation, EX_CONSTANT);
			if (dec->mType == DT_ARGUMENT)
			{
				exp->mDecType = TheUnsignedIntTypeDeclaration;
			}
			else if (dec->mType == DT_VARIABLE && (dec->mFlags & DTF_CONSTEXPR) && dec->mValue && dec->mValue->mType == EX_CONSTANT)
			{
				Declaration* dt = dec->mValue->mDecValue;
				if (dt->mType == DT_CONST_INTEGER)
				{
					exp->mDecValue = dt;
					exp->mDecType = dt->mBase;
					mScanner->NextToken();
					return exp;
				}
				else if (dt->mType == DT_CONST_ADDRESS)
				{
					dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
					dec->mInteger = dt->mInteger;
					dec->mBase = TheUnsignedIntTypeDeclaration;

					exp->mDecValue = dec;
					exp->mDecType = TheUnsignedIntTypeDeclaration;
					mScanner->NextToken();
					return exp;
				}
				exp->mDecType = TheUnsignedIntTypeDeclaration;
			}
			else if (dec->mType == DT_CONST_ASSEMBLER)
			{
				exp->mDecType = dec->mBase;
			}
			else if (dec->mType == DT_TYPE_STRUCT)
			{				
				mScanner->NextToken();

				int offset = 0;
				while (dec->mType == DT_TYPE_STRUCT && ConsumeTokenIf(TK_COLCOLON))
				{
					if (mScanner->mToken == TK_IDENT)
					{
						Declaration* edec = dec->mScope->Lookup(mScanner->mTokenIdent);
						if (edec)
						{
							offset += edec->mOffset;
							dec = edec->mBase;
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member not found", mScanner->mTokenIdent);

						mScanner->NextToken();
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Identifier for qualification expected");
				}

				dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
				dec->mInteger = offset;
				dec->mBase = TheUnsignedIntTypeDeclaration;
				exp = new Expression(mScanner->mLocation, EX_CONSTANT);
				exp->mDecValue = dec;
				exp->mDecType = dec->mBase;

				return exp;
			}
			else
				exp->mDecType = TheUnsignedIntTypeDeclaration;
		}

		exp->mDecValue = dec;

		mScanner->NextToken();

		while (ConsumeTokenIf(TK_DOT))
		{
			if (mScanner->mToken == TK_IDENT)
			{
				if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
				{
					Declaration* ldec = exp->mDecValue->mBase->mScope->Lookup(mScanner->mTokenIdent);
					if (ldec)
					{
						exp->mDecValue = ldec;
						exp->mDecType = TheUnsignedIntTypeDeclaration;
					}
					else if (exp->mDecValue->mFlags & DTF_DEFINED)
						mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Assembler label not found", mScanner->mTokenIdent);
					else
					{
						Declaration * ldec = new Declaration(mScanner->mLocation, DT_LABEL);
						ldec->mIdent = mScanner->mTokenIdent;
						ldec->mQualIdent = mScanner->mTokenIdent;
						exp->mDecType = TheUnsignedIntTypeDeclaration;
						exp->mDecValue->mBase->mScope->Insert(ldec->mIdent, ldec);
						exp->mDecValue = ldec;
					}
				}
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Identifier for qualification expected");
		}

		if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
		{
			Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL);
			ndec->mIdent = exp->mDecValue->mIdent;
			ndec->mQualIdent = exp->mDecValue->mQualIdent;
			ndec->mBase = exp->mDecValue;
			ndec->mInteger = 0;
			exp->mDecValue = ndec;
			exp->mDecType = TheUnsignedIntTypeDeclaration;
		}

		break;
	default:
		mErrors->Error(mScanner->mLocation, EERR_ASM_INVALD_OPERAND, "Invalid assembler operand");
	}

	if (!exp)
	{
		exp = new Expression(mScanner->mLocation, EX_VOID);
		exp->mDecType = TheVoidTypeDeclaration;
		exp->mDecValue = TheConstVoidValueDeclaration;
	}

	return exp;
}

Expression* Parser::ParseAssemblerMulOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = ParseAssemblerBaseOperand(pcasm, pcoffset);
	while (mScanner->mToken == TK_MUL || mScanner->mToken == TK_DIV || mScanner->mToken == TK_MOD)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssemblerBaseOperand(pcasm, pcoffset);
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}
	return exp;
}

Expression* Parser::ParseAssemblerAddOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = ParseAssemblerMulOperand(pcasm, pcoffset);
	while (mScanner->mToken == TK_ADD || mScanner->mToken == TK_SUB)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssemblerMulOperand(pcasm, pcoffset);
		if (!nexp->mLeft->mDecValue || !nexp->mRight->mDecValue)
		{
			mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Invalid assembler operand");
		}
		else if (nexp->mLeft->mDecValue->mType == DT_VARIABLE || nexp->mLeft->mDecValue->mType == DT_ARGUMENT)
		{
			if (nexp->mRight->mDecValue->mType == DT_CONST_INTEGER)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
				ndec->mBase = nexp->mLeft->mDecValue;
				ndec->mOffset = nexp->mToken == TK_SUB ? -int(nexp->mRight->mDecValue->mInteger) : int(nexp->mRight->mDecValue->mInteger);
				exp = new Expression(mScanner->mLocation, EX_CONSTANT);
				exp->mDecValue = ndec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Integer offset expected");
		}
		else if (nexp->mLeft->mDecValue->mType == DT_CONST_FUNCTION)
		{
			if (nexp->mRight->mDecValue->mType == DT_CONST_INTEGER)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_FUNCTION_REF);
				ndec->mBase = nexp->mLeft->mDecValue;
				ndec->mOffset = nexp->mToken == TK_SUB ? -int(nexp->mRight->mDecValue->mInteger) : int(nexp->mRight->mDecValue->mInteger);
				exp = new Expression(mScanner->mLocation, EX_CONSTANT);
				exp->mDecValue = ndec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Integer offset expected");
		}
		else if (nexp->mLeft->mDecValue->mType == DT_LABEL)
		{
			if (nexp->mRight->mDecValue->mType == DT_CONST_INTEGER)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
				ndec->mBase = nexp->mLeft->mDecValue;
				ndec->mOffset = nexp->mToken == TK_SUB ? -int(nexp->mRight->mDecValue->mInteger) : int(nexp->mRight->mDecValue->mInteger);
				exp = new Expression(mScanner->mLocation, EX_CONSTANT);
				exp->mDecValue = ndec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Integer offset expected");
		}
		else
			exp = nexp->ConstantFold(mErrors, mDataSection);
	}
	return exp;
}

Expression* Parser::ParseAssemblerShiftOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = ParseAssemblerAddOperand(pcasm, pcoffset);
	while (mScanner->mToken == TK_LEFT_SHIFT || mScanner->mToken == TK_RIGHT_SHIFT)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssemblerAddOperand(pcasm, pcoffset);
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}
	return exp;
}


Expression* Parser::ParseAssemblerAndOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = ParseAssemblerShiftOperand(pcasm, pcoffset);
	while (mScanner->mToken == TK_BINARY_AND)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssemblerShiftOperand(pcasm, pcoffset);
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}
	return exp;
}

Expression* Parser::ParseAssemblerOrOperand(Declaration* pcasm, int pcoffset)
{
	Expression* exp = ParseAssemblerAndOperand(pcasm, pcoffset);
	while (mScanner->mToken == TK_BINARY_OR)
	{
		Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
		nexp->mToken = mScanner->mToken;
		nexp->mLeft = exp;
		mScanner->NextToken();
		nexp->mRight = ParseAssemblerAndOperand(pcasm, pcoffset);
		exp = nexp->ConstantFold(mErrors, mDataSection);
	}
	return exp;
}


Expression* Parser::ParseAssemblerOperand(Declaration* pcasm, int pcoffset)
{
	if (mScanner->mToken == TK_LESS_THAN)
	{
		mScanner->NextToken();
		Expression* exp = ParseAssemblerOperand(pcasm, pcoffset);

		if (exp->mType == EX_CONSTANT)
		{
			if (exp->mDecValue->mType == DT_CONST_INTEGER)
			{
				Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
				dec->mInteger = exp->mDecValue->mInteger & 0xff;
				dec->mBase = TheUnsignedIntTypeDeclaration;
				exp->mDecValue = dec;			
			}
			else if (exp->mDecValue->mType == DT_LABEL)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_LABEL_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_VARIABLE)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_VARIABLE_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_CONST_FUNCTION)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_FUNCTION_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_FUNCTION_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_FUNCTION_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_LOWER_BYTE;
				exp->mDecValue = ndec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Label or integer value for lower byte operator expected");
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Constant for lower byte operator expected");

		return exp;
	}
	else if (mScanner->mToken == TK_GREATER_THAN)
	{
		mScanner->NextToken();
		Expression* exp = ParseAssemblerOperand(pcasm, pcoffset);

		if (exp->mType == EX_CONSTANT)
		{
			if (exp->mDecValue->mType == DT_CONST_INTEGER)
			{
				Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
				dec->mInteger = (exp->mDecValue->mInteger >> 8) & 0xff;
				dec->mBase = TheUnsignedIntTypeDeclaration;
				exp->mDecValue = dec;
			}
			else if (exp->mDecValue->mType == DT_LABEL)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_LABEL_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_VARIABLE)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_VARIABLE_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_CONST_FUNCTION)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_FUNCTION_REF);
				ndec->mBase = exp->mDecValue;
				ndec->mOffset = 0;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else if (exp->mDecValue->mType == DT_FUNCTION_REF)
			{
				Declaration* ndec = new Declaration(mScanner->mLocation, DT_FUNCTION_REF);
				ndec->mBase = exp->mDecValue->mBase;
				ndec->mOffset = exp->mDecValue->mOffset;
				ndec->mFlags |= DTF_UPPER_BYTE;
				exp->mDecValue = ndec;
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Label or integer value for lower byte operator expected");
		}
		else
			mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Constant for upper byte operator expected");

		return exp;
	}
	else
		return ParseAssemblerOrOperand(pcasm, pcoffset);
}

void Parser::AddAssemblerRegister(const Ident* ident, int value)
{
	Declaration* decaccu = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
	decaccu->mIdent = ident;
	decaccu->mQualIdent = ident;
	decaccu->mBase = TheUnsignedIntTypeDeclaration;
	decaccu->mSize = 2;
	decaccu->mInteger = value;
	mScope->Insert(decaccu->mIdent, decaccu);
}

Expression* Parser::ParseAssembler(Declaration* vdasm)
{
	Declaration* dasm;
	if (!vdasm)
	{
		dasm = new Declaration(mScanner->mLocation, DT_TYPE_ASSEMBLER);
		dasm->mScope = new DeclarationScope(mScope, SLEVEL_LOCAL);

		vdasm = new Declaration(mScanner->mLocation, DT_CONST_ASSEMBLER);
		vdasm->mVarIndex = -1;
		vdasm->mSection = mCodeSection;

		vdasm->mBase = dasm;
	}
	else
		dasm = vdasm->mBase;


	if (!(mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER))
		vdasm->mFlags |= DTF_VOLATILE;

	if (!(vdasm->mFlags & DTF_VOLATILE))
		vdasm->mFlags |= DTF_ASM_PRESERVE_A | DTF_ASM_PRESERVE_X | DTF_ASM_PRESERVE_Y;

	DeclarationScope* scope = dasm->mScope;
	mScope = scope;

	mScanner->SetAssemblerMode(true);

	AddAssemblerRegister(Ident::Unique("__tmpy"), BC_REG_WORK_Y);
	AddAssemblerRegister(Ident::Unique("__tmp"), BC_REG_WORK);
	AddAssemblerRegister(Ident::Unique("__ip"), BC_REG_IP);
	AddAssemblerRegister(Ident::Unique("__accu"), BC_REG_ACCU);
	AddAssemblerRegister(Ident::Unique("__addr"), BC_REG_ADDR);
	AddAssemblerRegister(Ident::Unique("__fp"), BC_REG_LOCALS);
	AddAssemblerRegister(Ident::Unique("__sp"), BC_REG_STACK);
	AddAssemblerRegister(Ident::Unique("__sregs"), BC_REG_TMP_SAVED);
	AddAssemblerRegister(Ident::Unique("__regs"), BC_REG_TMP);

	AddAssemblerRegister(Ident::Unique("accu"), BC_REG_ACCU);

	Declaration* decaccu = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
	decaccu->mIdent = Ident::Unique("accu");
	decaccu->mQualIdent = decaccu->mIdent;
	decaccu->mBase = TheUnsignedIntTypeDeclaration;
	decaccu->mSize = 2;
	decaccu->mInteger = BC_REG_ACCU;
	mScope->Insert(decaccu->mIdent, decaccu);


	Expression* ifirst = new Expression(mScanner->mLocation, EX_ASSEMBLER);
	Expression* ilast = ifirst, * ifinal = ifirst;

	bool		exitLabel = false;

	ifirst->mDecType = dasm;
	ifirst->mDecValue = vdasm;
	vdasm->mValue = ifirst;

	int		offset = 0;

	while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF)
	{
		if (mScanner->mToken == TK_IDENT)
		{
			AsmInsType	ins = FindAsmInstruction(mScanner->mTokenIdent->mString);
			if (ins == ASMIT_INV)
			{
				const Ident* label = mScanner->mTokenIdent;
				mScanner->NextToken();
				if (mScanner->mToken != TK_COLON)
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "':' expected");
				else
					mScanner->NextToken();

				exitLabel = true;

				Declaration* dec = mScope->Lookup(label, SLEVEL_STATIC);
				if (dec)
				{
					if (dec->mType != DT_LABEL || dec->mBase)
						mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate label definition");
				}
				else
					dec = new Declaration(mScanner->mLocation, DT_LABEL);

				dec->mIdent = label;
				dec->mQualIdent = dec->mIdent;
				dec->mValue = ilast;
				dec->mInteger = offset;
				dec->mBase = vdasm;
				mScope->Insert(dec->mIdent, dec);
			}
			else
			{
				exitLabel = false;

				ilast->mAsmInsType = ins;
				mScanner->NextToken();
				if (ins == ASMIT_BYTE)
				{
					for (;;)
					{
						ilast->mAsmInsMode = ASMIM_IMMEDIATE;
						if (mScanner->mToken == TK_STRING)
						{
							if (mScanner->mTokenString[0])
							{
								int i = 0;
								while (mScanner->mTokenString[i])
								{
									Declaration* dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
									dec->mInteger = mCharMap[mScanner->mTokenString[i]];
									dec->mBase = TheUnsignedCharTypeDeclaration;
									Expression* exp = new Expression(mScanner->mLocation, EX_CONSTANT);
									exp->mDecValue = dec;
									exp->mDecType = dec->mBase;
									ilast->mLeft = exp;

									i++;
									if (mScanner->mTokenString[i])
									{
										offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);

										ifinal = ilast;

										ilast->mRight = new Expression(mScanner->mLocation, EX_ASSEMBLER);
										ilast = ilast->mRight;
										ilast->mAsmInsType = ASMIT_BYTE;
										ilast->mAsmInsMode = ASMIM_IMMEDIATE;
									}
								}
							}
							else
								mErrors->Error(mScanner->mLocation, EERR_ASM_INVALID_INSTRUCTION, "Invalid assembler token");
							mScanner->NextToken();
						}
						else
							ilast->mLeft = ParseAssemblerOperand(vdasm, offset);
						if (ConsumeTokenIf(TK_COMMA))
						{
							offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);

							ifinal = ilast;

							ilast->mRight = new Expression(mScanner->mLocation, EX_ASSEMBLER);
							ilast = ilast->mRight;
							ilast->mAsmInsType = ASMIT_BYTE;
						}
						else
							break;
					}
				}
				else if (mScanner->mToken == TK_EOL || mScanner->mToken == TK_CLOSE_BRACE || mScanner->mToken == TK_SEMICOLON || mScanner->mToken == TK_COLON)
					ilast->mAsmInsMode = ASMIM_IMPLIED;
				else if (mScanner->mToken == TK_HASH)
				{
					ilast->mAsmInsMode = ASMIM_IMMEDIATE;
					mScanner->NextToken();
					ilast->mLeft = ParseAssemblerOperand(vdasm, offset);
				}
				else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
				{
					mScanner->NextToken();
					ilast->mLeft = ParseAssemblerOperand(vdasm, offset);
					if (mScanner->mToken == TK_COMMA)
					{
						mScanner->NextToken();
						if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "x") || !strcmp(mScanner->mTokenIdent->mString, "X")))
						{
							ilast->mAsmInsMode = ASMIM_INDIRECT_X;
							mScanner->NextToken();
							if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
								mScanner->NextToken();
							else
								mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected");
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "',x' expected");
					}
					else if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
					{
						mScanner->NextToken();
						if (mScanner->mToken == TK_COMMA)
						{
							mScanner->NextToken();
							if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "y") || !strcmp(mScanner->mTokenIdent->mString, "Y")))
							{
								ilast->mAsmInsMode = ASMIM_INDIRECT_Y;
								mScanner->NextToken();
							}
							else
								mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "',y' expected");
						}
						else
						{
							ilast->mAsmInsMode = ASMIM_INDIRECT;
						}
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "',' or ')' expected");
				}
				else
				{
					ilast->mLeft = ParseAssemblerOperand(vdasm, offset);
					if (mScanner->mToken == TK_COMMA)
					{
						mScanner->NextToken();
						if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "x") || !strcmp(mScanner->mTokenIdent->mString, "X")))
						{
							ilast->mAsmInsMode = ASMIM_ABSOLUTE_X;
							mScanner->NextToken();
						}
						else if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "y") || !strcmp(mScanner->mTokenIdent->mString, "Y")))
						{
							ilast->mAsmInsMode = ASMIM_ABSOLUTE_Y;
							mScanner->NextToken();
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "',x' or ',y' expected");
					}
					else
					{
						if (HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_RELATIVE))
							ilast->mAsmInsMode = ASMIM_RELATIVE;
						else if (
							HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_IMMEDIATE) &&
							ilast->mLeft &&
							ilast->mLeft->mType == EX_CONSTANT && 
							ilast->mLeft->mDecValue->mType == DT_VARIABLE &&
							(ilast->mLeft->mDecValue->mFlags & DTF_CONST) && 
							(ilast->mLeft->mDecValue->mFlags & DTF_STATIC) &&
							ilast->mLeft->mDecType->IsIntegerType() && 
							ilast->mLeft->mDecValue->mValue &&
							ilast->mLeft->mDecValue->mValue->mType == EX_CONSTANT)
						{
							ilast->mAsmInsMode = ASMIM_IMMEDIATE;
							ilast->mLeft = ilast->mLeft->mDecValue->mValue;
						}
						else
							ilast->mAsmInsMode = ASMIM_ABSOLUTE;
					}
				}

				if (ilast->mLeft && ilast->mLeft->mDecValue)
				{
					if ((ilast->mLeft->mDecValue->mType == DT_CONST_INTEGER && ilast->mLeft->mDecValue->mInteger >= 0 && ilast->mLeft->mDecValue->mInteger < 256) ||
						(ilast->mLeft->mDecValue->mType == DT_VARIABLE_REF && !(ilast->mLeft->mDecValue->mBase->mFlags & DTF_GLOBAL)) ||
						(ilast->mLeft->mDecValue->mType == DT_VARIABLE && !(ilast->mLeft->mDecValue->mFlags & DTF_GLOBAL)) ||
						(ilast->mLeft->mDecValue->mType == DT_VARIABLE && (ilast->mLeft->mDecValue->mFlags & DTF_ZEROPAGE)) ||
						ilast->mLeft->mDecValue->mType == DT_ARGUMENT)
					{
						if (ilast->mAsmInsMode == ASMIM_ABSOLUTE && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE))
							ilast->mAsmInsMode = ASMIM_ZERO_PAGE;
						else if (ilast->mAsmInsMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE_X))
							ilast->mAsmInsMode = ASMIM_ZERO_PAGE_X;
						else if (ilast->mAsmInsMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE_Y))
							ilast->mAsmInsMode = ASMIM_ZERO_PAGE_Y;
					}
				}

				offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);

				uint32 flags = AsmInsFlags(ilast->mAsmInsType, ilast->mAsmInsMode);
				if (ConsumeTokenIf(TK_COLON))
				{
					flags &= ~(ASMIFLG_USES_ACCU | ASMIFLG_USES_XREG | ASMIFLG_USES_YREG | ASMIFLG_CHANGES_ACCU | ASMIFLG_CHANGES_XREG | ASMIFLG_CHANGES_YREG);

					if (mScanner->mToken == TK_IDENT)
					{
						char* cp = mScanner->mTokenIdent->mString;
						while (*cp)
						{
							switch (*cp)
							{
							case 'a':
							case 'A':
								flags |= ASMIFLG_USES_ACCU;
								break;
							case 'x':
							case 'X':
								flags |= ASMIFLG_USES_XREG;
								break;
							case 'y':
							case 'Y':
								flags |= ASMIFLG_USES_YREG;
								break;
							default:
								mErrors->Error(mScanner->mLocation, EERR_ASM_INVALID_REGISTER, "Invalid register specified", mScanner->mTokenIdent);
							}
							cp++;
						}
						mScanner->NextToken();
					}
					ConsumeToken(TK_ARROW);
					if (mScanner->mToken == TK_IDENT)
					{
						char* cp = mScanner->mTokenIdent->mString;
						while (*cp)
						{
							switch (*cp)
							{
							case 'a':
							case 'A':
								flags |= ASMIFLG_CHANGES_ACCU;
								break;
							case 'x':
							case 'X':
								flags |= ASMIFLG_CHANGES_XREG;
								break;
							case 'y':
							case 'Y':
								flags |= ASMIFLG_CHANGES_YREG;
								break;
							default:
								mErrors->Error(mScanner->mLocation, EERR_ASM_INVALID_REGISTER, "Invalid register specified", mScanner->mTokenIdent);
							}
							cp++;
						}
						mScanner->NextToken();
					}
				}

				if (flags & ASMIFLG_CHANGES_ACCU) 	vdasm->mFlags &= ~DTF_ASM_PRESERVE_A;
				if (flags & ASMIFLG_CHANGES_XREG) 	vdasm->mFlags &= ~DTF_ASM_PRESERVE_X;
				if (flags & ASMIFLG_CHANGES_YREG) 	vdasm->mFlags &= ~DTF_ASM_PRESERVE_Y;

				ifinal = ilast;

				ilast->mRight = new Expression(mScanner->mLocation, EX_ASSEMBLER);
				ilast = ilast->mRight;

				if (mScanner->mToken != TK_EOL && mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_SEMICOLON)
				{
					mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "End of line expected");
				}

				while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_EOF && mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_SEMICOLON)
					mScanner->NextToken();
			}
		}
		else if (mScanner->mToken == TK_EOL || mScanner->mToken == TK_SEMICOLON)
		{
			mScanner->NextToken();
		}
		else
		{
			mErrors->Error(mScanner->mLocation, EERR_ASM_INVALID_INSTRUCTION, "Invalid assembler token");

			while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_SEMICOLON && mScanner->mToken != TK_EOF)
				mScanner->NextToken();
		 }
	}

	if ((ifinal->mAsmInsType == ASMIT_RTS || ifinal->mAsmInsType == ASMIT_JMP) && !exitLabel)
	{
		delete ilast;
		ilast = ifinal;
		ifinal->mRight = nullptr;
	}
	else
	{
		ilast->mAsmInsType = ASMIT_RTS;
		ilast->mAsmInsMode = ASMIM_IMPLIED;
	}

#if 0
	offset = 0;
	ilast = ifirst;
	while (ilast)
	{
		if (ilast->mLeft && ilast->mLeft->mType == EX_UNDEFINED)
		{
			Declaration* dec = mScope->Lookup(ilast->mLeft->mDecValue->mIdent);
			if (dec)
			{
				ilast->mLeft->mType = EX_CONSTANT;
				ilast->mLeft->mDecValue = dec;
			}
			else
				mErrors->Error(ilast->mLeft->mLocation, "Undefined label", ilast->mLeft->mDecValue->mIdent->mString);
		}
		offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);

		ilast = ilast->mRight;
	}
#endif

	mScope->End(mScanner->mLocation);
	mScope = mScope->mParent;
	dasm->mSize = offset;
	dasm->mScope->mParent = nullptr;

	mScanner->SetAssemblerMode(false);

	vdasm->mFlags |= DTF_DEFINED;

	return ifirst;
}

bool Parser::ExpectToken(Token token)
{
	if (mScanner->mToken == token)
	{
		return true;
	}
	else
	{
		char	buffer[100];
		sprintf_s(buffer, "%s expected", TokenNames[token]);
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, buffer);
		return false;
	}
}

bool Parser::ConsumeToken(Token token)
{
	if (mScanner->mToken == token)
	{
		mScanner->NextToken();
		return true;
	}
	else
	{
		char	buffer[100];
		sprintf_s(buffer, "%s expected", TokenNames[token]);
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, buffer);
		return false;
	}
}

bool Parser::ConsumeTokenIf(Token token)
{
	if (mScanner->mToken == token)
	{
		mScanner->NextToken();
		return true;
	}
	else
		return false;
}

bool Parser::ConsumeIdentIf(const char* ident)
{
	if (mScanner->mToken == TK_IDENT && !strcmp(ident, mScanner->mTokenIdent->mString))
	{
		mScanner->NextToken();
		return true;
	}
	else
		return false;
}

bool Parser::IsTypeToken(void)
{
	switch (mScanner->mToken)
	{
	case TK_INT:
	case TK_SHORT:
	case TK_LONG:
	case TK_FLOAT:
	case TK_CHAR:
	case TK_BOOL:
	case TK_VOID:
	case TK_UNSIGNED:
	case TK_SIGNED:
	case TK_CONST:
	case TK_VOLATILE:
	case TK_STRUCT:
	case TK_CLASS:
	case TK_UNION:
	case TK_ENUM:
	case TK_TYPEDEF:
	case TK_STATIC:
	case TK_AUTO:
	case TK_STRIPED:
	case TK_DECLTYPE:
		return true;
	case TK_IDENT:
	{
		const Ident* pident = mScanner->mTokenIdent;

		if (mTemplateScope && mTemplateScope->Lookup(pident))
			return true;

		Declaration* dec = nullptr;

		if (mThisPointer && !mScope->Lookup(pident, SLEVEL_FUNCTION))
		{
			int offset;
			uint64 flags;

			if (mThisPointer->mType == DT_ARGUMENT)
				dec = MemberLookup(mThisPointer->mBase->mBase, mScanner->mTokenIdent, offset, flags);
			else if (mThisPointer->mType == DT_TYPE_POINTER)
				dec = MemberLookup(mThisPointer->mBase, mScanner->mTokenIdent, offset, flags);
		}

		if (!dec)
			dec = mScope->Lookup(pident);

		if (!dec)
			return true;

		if (dec->mType <= DT_TYPE_AUTO)
			return true;

	
	}	break;

	}

	return false;
}

bool Parser::IsIntegerToken(void)
{
	return (mScanner->mToken == TK_INTEGER || mScanner->mToken == TK_INTEGERL || mScanner->mToken == TK_INTEGERU || mScanner->mToken == TK_INTEGERUL);
}

void Parser::ParsePragma(void)
{
	uint64 op = mScanner->mCompilerOptions;
	mScanner->mCompilerOptions &= ~COPT_PETSCII;

	if (mScanner->mToken == TK_IDENT)
	{
		if (!strcmp(mScanner->mTokenIdent->mString, "message"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_STRING)
			{
				printf("%s\n", mScanner->mTokenString);
				mScanner->NextToken();
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "warning"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (ConsumeIdentIf("disable"))
			{
				ConsumeToken(TK_COLON);
				do {
					if (ExpectToken(TK_INTEGER) && mScanner->mTokenInteger < EERR_GENERIC)
					{
						mErrors->mDisabled += int(mScanner->mTokenInteger);
						mScanner->NextToken();
					}
				} while (ConsumeTokenIf(TK_COMMA));
			}
			else if (ConsumeToken(TK_DEFAULT))
			{
				ConsumeToken(TK_COLON);
				do {
					if (ExpectToken(TK_INTEGER) && mScanner->mTokenInteger < EERR_GENERIC)
					{
						mErrors->mDisabled -= int(mScanner->mTokenInteger);
						mScanner->NextToken();
					}
				} while (ConsumeTokenIf(TK_COMMA));
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "once"))
		{
			mScanner->MarkSourceOnce();
			mScanner->NextToken();
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "compile"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_STRING)
			{
				mCompilationUnits->AddUnit(mScanner->mLocation, (const char *)mScanner->mTokenString, mScanner->mLocation.mFileName);
				mScanner->NextToken();
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "intrinsic"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_CONST_FUNCTION)
					dec->mFlags |= DTF_INTRINSIC;
				else
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Intrinsic function not found");
				mScanner->NextToken();
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "native"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (!dec)
					dec = mScope->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_CONST_FUNCTION)
					dec->mFlags |= DTF_NATIVE;
				else
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Native function not found");
				mScanner->NextToken();
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "startup"))
		{
			if (mCompilationUnits->mStartup)
				mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate startup pragma");

			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_CONST_ASSEMBLER)
					mCompilationUnits->mStartup = dec;
				else
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Startup function not found");
				mScanner->NextToken();
			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "register"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* reg = mScanner->mTokenIdent;
				int	index = 0;
				mScanner->NextToken();

				ConsumeToken(TK_COMMA);
				Expression* exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER && exp->mDecValue->mInteger >= 2 && exp->mDecValue->mInteger < 0x100)
					index = int(exp->mDecValue->mInteger);
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for start expected");

				if (!strcmp(reg->mString, "__tmpy"))
					BC_REG_WORK_Y = index;
				else if (!strcmp(reg->mString, "__tmp"))
					BC_REG_WORK = index;
				else if (!strcmp(reg->mString, "__ip"))
					BC_REG_IP = index;
				else if (!strcmp(reg->mString, "__accu"))
					BC_REG_ACCU = index;
				else if (!strcmp(reg->mString, "__addr"))
					BC_REG_ADDR = index;
				else if (!strcmp(reg->mString, "__sp"))
					BC_REG_STACK = index;
				else if (!strcmp(reg->mString, "__fp"))
					BC_REG_LOCALS = index;
				else if (!strcmp(reg->mString, "__sregs"))
					BC_REG_TMP_SAVED = index;
				else if (!strcmp(reg->mString, "__regs"))
					BC_REG_TMP = index;
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Unknown register name");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Register name expected");
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "bytecode"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			Expression* exp = ParseAssemblerOperand(nullptr, 0);

			ConsumeToken(TK_COMMA);
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_CONST_ASSEMBLER)
				{
					mScanner->NextToken();
					if (ConsumeTokenIf(TK_DOT))
					{
						if (mScanner->mToken == TK_IDENT)
						{
							Declaration* ndec = dec->mBase->mScope->Lookup(mScanner->mTokenIdent);
							if (ndec)
								dec = ndec;
							else
								mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Label not found in assembler code");
							mScanner->NextToken();
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
					}

					if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER && exp->mDecValue->mInteger >= 0 && exp->mDecValue->mInteger < 256)
					{
						if (mCompilationUnits->mByteCodes[exp->mDecValue->mInteger])
							mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate bytecode function");

						mCompilationUnits->mByteCodes[exp->mDecValue->mInteger] = dec;
					}
					else
						mErrors->Error(exp->mLocation, EERR_CONSTANT_TYPE, "Numeric value for byte code expected");
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Bytecode function not found");
					mScanner->NextToken();
				}

			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "runtime"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			const Ident* rtident = nullptr;

			if (mScanner->mToken == TK_IDENT)
			{
				rtident = mScanner->mTokenIdent;
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");

			ConsumeToken(TK_COMMA);
			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_CONST_ASSEMBLER)
				{
					mScanner->NextToken();
					if (ConsumeTokenIf(TK_DOT))
					{
						if (mScanner->mToken == TK_IDENT)
						{
							Declaration* ndec = dec->mBase->mScope->Lookup(mScanner->mTokenIdent);
							if (ndec)
								dec = ndec;
							else
								mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Label not found in assembler code");
							mScanner->NextToken();
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
					}

					if (rtident)
						mCompilationUnits->mRuntimeScope->Insert(rtident, dec);
				}
				else if (dec && dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL))
				{
					if (rtident)
						mCompilationUnits->mRuntimeScope->Insert(rtident, dec);
					mScanner->NextToken();
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Runtime function not found", rtident);
					mScanner->NextToken();
				}

			}
			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "stacksize"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (IsIntegerToken())
			{
				mCompilationUnits->mSectionStack->mSize = int(mScanner->mTokenInteger);
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Stack size expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "heapsize"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (IsIntegerToken())
			{
				mCompilationUnits->mSectionHeap->mSize = int(mScanner->mTokenInteger);
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Heap size expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "charmap"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (IsIntegerToken())
			{
				int	cindex = int(mScanner->mTokenInteger);
				mScanner->NextToken();
				ConsumeToken(TK_COMMA);

				if (IsIntegerToken())
				{
					int	ccode = int(mScanner->mTokenInteger);
					int	ccount = 1;
					mScanner->NextToken();
					if (ConsumeTokenIf(TK_COMMA))
					{
						if (IsIntegerToken())
						{
							ccount = int(mScanner->mTokenInteger);
							mScanner->NextToken();
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Character run expected");
					}

					for (int i = 0; i < ccount; i++)
					{
						mCharMap[cindex] = ccode;
						cindex = (cindex + 1) & 255;
						ccode = (ccode + 1) & 255;
					}
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Character code expected");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Character index expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "region"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* regionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();

				Expression* exp;
				int	start = 0, end = 0, flags = 0;
				uint64	bank = 0;

				ConsumeToken(TK_COMMA);
				
				exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_ADDRESS))
					start = int(exp->mDecValue->mInteger);
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for start expected");
				
				ConsumeToken(TK_COMMA);
				
				exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && (exp->mDecValue->mType == DT_CONST_INTEGER || exp->mDecValue->mType == DT_CONST_ADDRESS))
					end = int(exp->mDecValue->mInteger);
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for end expected");
				
				ConsumeToken(TK_COMMA);

				if (mScanner->mToken != TK_COMMA)
				{
					exp = ParseRExpression();
					if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
						flags = int(exp->mDecValue->mInteger);
					else
						mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for flags expected");
				}

				ConsumeToken(TK_COMMA);

				Declaration* inlay = nullptr;

				if (mScanner->mToken != TK_COMMA)
				{
					if (mScanner->mToken == TK_OPEN_BRACE)
					{
						do
						{
							mScanner->NextToken();

							exp = ParseRExpression();
							if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
								bank |= 1ULL << exp->mDecValue->mInteger;
							else
								mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected");

						} while (mScanner->mToken == TK_COMMA);

						ConsumeToken(TK_CLOSE_BRACE);
					}
					else
					{
						exp = ParseExpression(true);
						if (exp->mType == EX_VARIABLE && exp->mDecType->mType == DT_TYPE_ARRAY && exp->mDecType->mSize == 0 &&
							exp->mDecType->mBase->mType == DT_TYPE_INTEGER && exp->mDecType->mBase->mSize == 1)
						{
							exp->mDecValue->mFlags |= DTF_DEFINED | DTF_BANK_INLAY;
							exp->mDecValue->mSection = mCodeSection;
							exp->mDecType->mFlags |= DTF_DEFINED;
							inlay = exp->mDecValue;
						}
						else
						{
							exp = exp->ConstantFold(mErrors, mDataSection, mCompilationUnits->mLinker);
							if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
								bank = 1ULL << exp->mDecValue->mInteger;
							else
								mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected");
						}
					}
				}

				LinkerRegion* rgn = mCompilationUnits->mLinker->FindRegion(regionIdent);
				if (!rgn)
				{
					rgn = mCompilationUnits->mLinker->AddRegion(regionIdent, start, end);
					rgn->mFlags = flags;
					rgn->mCartridgeBanks = bank;
				}
				else if (rgn->mStart != start || rgn->mEnd != end || rgn->mFlags != flags || rgn->mCartridgeBanks != bank)
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Conflicting linker region definition");

				if (inlay)
				{
					inlay->mInlayRegion = rgn;
				}

				ConsumeToken(TK_COMMA);
				ConsumeToken(TK_OPEN_BRACE);
				if (!ConsumeTokenIf(TK_CLOSE_BRACE))
				{
					do {
						if (mScanner->mToken == TK_IDENT)
						{
							LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(mScanner->mTokenIdent);
							if (lsec)
							{
								if (!rgn->mSections.Contains(lsec))
									rgn->mSections.Push(lsec);
							}
							else
								mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name not defined");
							mScanner->NextToken();
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");
					} while (ConsumeTokenIf(TK_COMMA));
					ConsumeToken(TK_CLOSE_BRACE);
				}

				if (ConsumeTokenIf(TK_COMMA))
				{
					exp = ParseRExpression();
					if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
						rgn->mReloc = int(exp->mDecValue->mInteger - rgn->mStart);
					else
						mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected");
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Region name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "overlay"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* overlayIdent = mScanner->mTokenIdent;
				mScanner->NextToken();

				int	bank = 0;

				ConsumeToken(TK_COMMA);

				Expression* exp;

				exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
					bank = int(exp->mDecValue->mInteger);
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for bank expected");

				LinkerOverlay* lovl = mCompilationUnits->mLinker->AddOverlay(mScanner->mLocation, overlayIdent, bank);
			}

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "section"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* sectionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();

				int	flags = 0;
				Expression* exp;
				Declaration* dstart = nullptr, * dend = nullptr;
				LinkerSectionType	type = LST_DATA;

				ConsumeToken(TK_COMMA);

				exp = ParseRExpression();
				if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
					flags = int(exp->mDecValue->mInteger);
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for flags expected");

				if (ConsumeTokenIf(TK_COMMA))
				{
					if (mScanner->mToken != TK_COMMA)
					{
						exp = ParseExpression(false);
						if (exp->mDecValue && exp->mDecValue->mType == DT_VARIABLE)
							dstart = exp->mDecValue;
					}

					if (ConsumeTokenIf(TK_COMMA))
					{
						if (mScanner->mToken != TK_COMMA)
						{
							exp = ParseExpression(false);
							if (exp->mDecValue && exp->mDecValue->mType == DT_VARIABLE)
								dend = exp->mDecValue;
						}

						if (ConsumeTokenIf(TK_COMMA))
						{
							if (mScanner->mToken == TK_IDENT)
							{
								if (!strcmp(mScanner->mTokenIdent->mString, "bss"))
									type = LST_BSS;
								else if (!strcmp(mScanner->mTokenIdent->mString, "data"))
									type = LST_DATA;
								else if (!strcmp(mScanner->mTokenIdent->mString, "packed"))
								{
									type = LST_DATA;
									flags |= LSECF_PACKED;
								}
								else
									mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Unknown section type");
							}
							else
								mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Identifier expected");

							mScanner->NextToken();

						}
					}
				}

				LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(sectionIdent);
				if (!lsec)
					lsec = mCompilationUnits->mLinker->AddSection(sectionIdent, type);

				lsec->mFlags |= flags;

				if (dstart)
				{
					dstart->mSection = lsec;
					dstart->mFlags |= DTF_SECTION_START;
				}
				if (dend)
				{
					dend->mSection = lsec;
					dend->mFlags |= DTF_SECTION_END;
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "place"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* sectionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();
				LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(sectionIdent);
				if (lsec)
				{
					while (ConsumeTokenIf(TK_COMMA))
					{
						if (mScanner->mToken == TK_IDENT)
						{
							Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
							if (dec && (dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL) || dec->mType == DT_CONST_FUNCTION))
							{
								mScanner->NextToken();

								dec->mFlags |= DTF_PLACED;
								dec->mSection = lsec;
								if (dec->mLinkerObject)
									dec->mLinkerObject->MoveToSection(lsec);
							}
							else
							{
								mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found");
								mScanner->NextToken();
							}
						}
						else
							mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Variable name expected");
					}
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section not defined");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "code"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* sectionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();
				LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(sectionIdent);
				if (lsec)
				{
					mCodeSection = lsec;
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section not defined");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "data"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* sectionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();
				LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(sectionIdent);
				if (lsec)
				{
					mDataSection = lsec;
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section not defined");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "bss"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* sectionIdent = mScanner->mTokenIdent;
				mScanner->NextToken();
				LinkerSection* lsec = mCompilationUnits->mLinker->FindSection(sectionIdent);
				if (lsec)
				{
					mBSSection = lsec;
				}
				else
					mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section not defined");
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Section name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "nocross"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL))
					dec->mFlags |= DTF_NO_PAGE_CROSS;
				else if (dec && dec->mType == DT_CONST_FUNCTION)
					dec->mFlags |= DTF_NO_PAGE_CROSS;
				else
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found");
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Variable name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "align"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL))
				{
					mScanner->NextToken();
					ConsumeToken(TK_COMMA);

					Expression * exp = ParseRExpression();
					if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
					{
						dec->mAlignment = int(exp->mDecValue->mInteger);
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for alignment expected");
				}
				else if (dec && dec->mType == DT_CONST_FUNCTION)
				{
					mScanner->NextToken();
					ConsumeToken(TK_COMMA);

					Expression* exp = ParseRExpression();
					if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
					{
						dec->mAlignment = int(exp->mDecValue->mInteger);
					}
					else
						mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer number for alignment expected");
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found");
					mScanner->NextToken();
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Variable name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "zeropage"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL))
				{
					mScanner->NextToken();

					dec->mFlags |= DTF_ZEROPAGE;
					dec->mSection = mCompilationUnits->mSectionZeroPage;
					if (dec->mLinkerObject)
					{
						dec->mLinkerObject->MoveToSection(dec->mSection);
						dec->mLinkerObject->mFlags |= LOBJF_ZEROPAGE;
					}
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found");
					mScanner->NextToken();
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Variable name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "reference"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			if (mScanner->mToken == TK_IDENT)
			{
				Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
				if (dec && (dec->mType == DT_CONST_FUNCTION || (dec->mType == DT_VARIABLE && (dec->mFlags & DTF_GLOBAL))))
				{
					mCompilationUnits->AddReferenced(dec);
					mScanner->NextToken();
				}
				else
				{
					mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Variable not found");
					mScanner->NextToken();
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Variable name expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "unroll"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);

			mUnrollLoopPage = false;

			if (IsIntegerToken())
			{
				mUnrollLoop = int(mScanner->mTokenInteger);
				mScanner->NextToken();
			}
			else if (mScanner->mToken == TK_IDENT && !strcmp(mScanner->mTokenIdent->mString, "full"))
			{
				mUnrollLoop = 0x10000;
				mScanner->NextToken();
			}
			else if (mScanner->mToken == TK_IDENT && !strcmp(mScanner->mTokenIdent->mString, "page"))
			{
				mUnrollLoop = 0x10000;
				mUnrollLoopPage = true;
				mScanner->NextToken();
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer literal expected");

			ConsumeToken(TK_CLOSE_PARENTHESIS);
		}
		else if (!strcmp(mScanner->mTokenIdent->mString, "callinline"))
		{
			mScanner->NextToken();
			ConsumeToken(TK_OPEN_PARENTHESIS);
			ConsumeToken(TK_CLOSE_PARENTHESIS);
			mInlineCall = true;
		}
		else if (ConsumeIdentIf("optimize"))
		{
			ConsumeToken(TK_OPEN_PARENTHESIS);
			if (!ConsumeTokenIf(TK_CLOSE_PARENTHESIS))
			{
				do {
					if (ConsumeIdentIf("push"))
					{
						if (mCompilerOptionSP < 32)
							mCompilerOptionStack[mCompilerOptionSP++] = mCompilerOptions;
						else
							mErrors->Error(mScanner->mLocation, ERRR_STACK_OVERFLOW, "Stack overflow");
					}
					else if (ConsumeIdentIf("pop"))
					{
						if (mCompilerOptionSP > 0)
							mCompilerOptions = mCompilerOptionStack[--mCompilerOptionSP];
						else
							mErrors->Error(mScanner->mLocation, ERRR_STACK_OVERFLOW, "Stack underflow");
					}
					else if (IsIntegerToken())
					{
						mCompilerOptions &= ~(COPT_OPTIMIZE_ALL);
						switch (mScanner->mTokenInteger)
						{
						case 0:
							break;
						case 1:
							mCompilerOptions |= COPT_OPTIMIZE_DEFAULT;
							break;
						case 2:
							mCompilerOptions |= COPT_OPTIMIZE_SPEED;
							break;
						case 3:
							mCompilerOptions |= COPT_OPTIMIZE_ALL;
							break;
						default:
							mErrors->Error(mScanner->mLocation, ERRR_INVALID_NUMBER, "Invalid number");
						}
						mScanner->NextToken();
					}
					else if (ConsumeIdentIf("asm"))
						mCompilerOptions |= COPT_OPTIMIZE_ASSEMBLER;
					else if (ConsumeIdentIf("noasm"))
						mCompilerOptions &= ~COPT_OPTIMIZE_ASSEMBLER;
					else if (ConsumeIdentIf("size"))
						mCompilerOptions |= COPT_OPTIMIZE_SIZE;
					else if (ConsumeIdentIf("speed"))
						mCompilerOptions &= ~COPT_OPTIMIZE_SIZE;
					else if (ConsumeIdentIf("noinline"))
						mCompilerOptions &= ~(COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL);
					else if (ConsumeTokenIf(TK_INLINE))
						mCompilerOptions |= COPT_OPTIMIZE_INLINE;
					else if (ConsumeIdentIf("autoinline"))
						mCompilerOptions |= COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE;
					else if (ConsumeIdentIf("maxinline"))
						mCompilerOptions |= COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL;
					else if (ConsumeIdentIf("constparams"))
						mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
					else if (ConsumeIdentIf("noconstparams"))
						mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS;
					else if (ConsumeIdentIf("outline"))
						mCompilerOptions |= COPT_OPTIMIZE_OUTLINE;
					else if (ConsumeIdentIf("nooutline"))
						mCompilerOptions &= ~COPT_OPTIMIZE_OUTLINE;
					else
						mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option");

				} while (ConsumeTokenIf(TK_COMMA));

				ConsumeToken(TK_CLOSE_PARENTHESIS);
			}
		}
		else
		{
			mScanner->NextToken();
			if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
			{
				while (mScanner->mToken != TK_CLOSE_PARENTHESIS && mScanner->mToken != TK_EOF)
					mScanner->NextToken();
				ConsumeToken(TK_CLOSE_PARENTHESIS);
			}
			mErrors->Error(mScanner->mLocation, EWARN_UNKNOWN_PRAGMA, "Unknown pragma, ignored", mScanner->mTokenIdent);
		}
	}
	else
		mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Invalid pragma directive");

	mScanner->mCompilerOptions = op;
}

void Parser::ParseNamespace(void)
{
	if (mScanner->mToken == TK_IDENT)
	{
		const Ident* ident = mScanner->mTokenIdent;

		mScanner->NextToken();

		if (mScanner->mToken == TK_OPEN_BRACE)
		{
			Declaration* ns = mScope->Lookup(ident);
			if (ns)
			{
				if (ns->mType != DT_NAMESPACE)
				{
					mErrors->Error(mScanner->mLocation, ERRO_NOT_A_NAMESPACE, "Not a namespace", ident);
					ns = nullptr;
				}
			}

			if (!ns)
			{
				ns = new Declaration(mScanner->mLocation, DT_NAMESPACE);
				ns->mScope = new DeclarationScope(mScope, SLEVEL_NAMESPACE, ident);
				ns->mIdent = ident;
				ns->mQualIdent = mScope->Mangle(ident);

				mScope->Insert(ident, ns);
			}

			mScanner->NextToken();

			DeclarationScope* outerScope = mScope;
			mScope = ns->mScope;

			while (mScanner->mToken != TK_EOF && mScanner->mToken != TK_CLOSE_BRACE)
			{
				if (mScanner->mToken == TK_PREP_PRAGMA)
				{
					mScanner->NextToken();
					ParsePragma();
				}
				else if (mScanner->mToken == TK_SEMICOLON)
					mScanner->NextToken();
				else if (mScanner->mToken == TK_TEMPLATE)
				{
					mScanner->NextToken();
					ParseTemplateDeclaration(nullptr);
				}
				else if (mScanner->mToken == TK_NAMESPACE)
				{
					mScanner->NextToken();
					ParseNamespace();
				}
				else if (mScanner->mToken == TK_STATIC_ASSERT)
				{
					mScanner->NextToken();
					ParseStaticAssert();
				}
				else
					ParseDeclaration(nullptr, true, false, false);
			}

			ConsumeToken(TK_CLOSE_BRACE);

			mScope = outerScope;
		}
		else
		{
			ConsumeToken(TK_ASSIGN);
			Declaration* dec = ParseQualIdent(false);
			if (dec)
			{
				if (dec->mType == DT_NAMESPACE)
				{
					Declaration* ns = mScope->Insert(ident, dec);
					if (ns)
					{
						mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition", ident);
						mErrors->Error(ns->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
					}
				}
				else
					mErrors->Error(mScanner->mLocation, ERRO_NOT_A_NAMESPACE, "Not a namespace", ident);
			}
			ConsumeToken(TK_SEMICOLON);
		}
	}
	else
	{
		// Anonymous namespace
	}
}

Location Parser::FullLocation(const Location& loc)
{
	if (mParent)
		return mParent->FullLocation(Location(loc, &mParent->mScanner->mLocation));
	else
		return loc;
}

void Parser::Parse(void)
{
	mLocalIndex = 0;

	while (mScanner->mToken != TK_EOF)
	{
		if (mScanner->mToken == TK_PREP_PRAGMA)
		{
			mScanner->NextToken();
			ParsePragma();
		}
		else if (mScanner->mToken == TK_ASM)
		{
			mScanner->NextToken();
			if (mScanner->mToken == TK_IDENT)
			{
				const Ident* ident = mScanner->mTokenIdent;
				mScanner->NextToken();

				Declaration* vdasm = mScope->Lookup(ident);
				if (vdasm)
				{
					if (vdasm->mType != DT_CONST_ASSEMBLER || (vdasm->mFlags & DTF_DEFINED))
					{
						mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition", ident);
						mErrors->Error(vdasm->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition");
					}
				}
				else
				{
					Declaration	*	dasm = new Declaration(mScanner->mLocation, DT_TYPE_ASSEMBLER);
					dasm->mScope = new DeclarationScope(mScope, SLEVEL_LOCAL);

					vdasm = new Declaration(mScanner->mLocation, DT_CONST_ASSEMBLER);
					vdasm->mVarIndex = -1;
					vdasm->mSection = mCodeSection;
					vdasm->mBase = dasm;
					vdasm->mIdent = ident;
					vdasm->mQualIdent = ident;
					mScope->Insert(ident, vdasm);
				}

				vdasm->mFlags |= ParseAssemblerFlags();

				if (mScanner->mToken == TK_OPEN_BRACE)
				{
					mScanner->NextToken();

					Expression* exp = ParseAssembler(vdasm);

					if (mScanner->mToken == TK_CLOSE_BRACE)
						mScanner->NextToken();
					else
						mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "'}' expected");
				}
			}
			else
				mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected");
		}
		else if (mScanner->mToken == TK_SEMICOLON)
			mScanner->NextToken();
		else if (mScanner->mToken == TK_TEMPLATE)
		{
			mScanner->NextToken();
			ParseTemplateDeclaration(nullptr);
		}
		else if (mScanner->mToken == TK_NAMESPACE)
		{
			mScanner->NextToken();
			ParseNamespace();
		}
		else if (mScanner->mToken == TK_STATIC_ASSERT)
		{
			mScanner->NextToken();
			ParseStaticAssert();
		}
		else
			ParseDeclaration(nullptr, true, false, false);
	}
}
