move all doom-specific loops out of common code

This commit is contained in:
Ricardo Luís Vaz Silva 2023-11-08 11:06:32 -03:00 committed by Rachael Alexanderson
parent 71999e7cf6
commit 4ec76afc40
8 changed files with 556 additions and 299 deletions

View file

@ -11402,6 +11402,9 @@ FxForEachLoop::~FxForEachLoop()
SAFE_DELETE(Code);
}
extern bool IsGameSpecificForEachLoop(FxForEachLoop *);
extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *);
FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
{
CHECKRESOLVED();
@ -11410,74 +11413,61 @@ FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
SAFE_RESOLVE(Array3, ctx);
SAFE_RESOLVE(Array4, ctx);
if(Array->ValueType->isMap() || Array->ValueType->isMapIterator())
{
auto mapLoop = new FxMapForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition);
auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition);
Array = Array2 = Array3 = Array4 = Code = nullptr;
delete this;
return mapLoop->Resolve(ctx);
}
else if(Array->ValueType->isObjectPointer() && (((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator))
else if(IsGameSpecificForEachLoop(this))
{
auto blockIt = new FxBlockIteratorForEachLoop(loopVarName, NAME_None, NAME_None, Array, Code, ScriptPosition);
delete Array2;
delete Array3;
delete Array4;
Array = Array2 = Array3 = Array4 = Code = nullptr;
delete this;
return blockIt->Resolve(ctx);
return ResolveGameSpecificForEachLoop(this)->Resolve(ctx);
}
else if(Array->ValueType->isObjectPointer() && (((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_ActorIterator || ((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_ThinkerIterator))
else
{
auto castIt = new FxCastForEachLoop(NAME_None, loopVarName, Array, Code, ScriptPosition);
delete Array2;
delete Array3;
delete Array4;
Array = Array2 = Array3 = Array4 = Code = nullptr;
// Instead of writing a new code generator for this, convert this into
//
// int @size = array.Size();
// for(int @i = 0; @i < @size; @i++)
// {
// let var = array[i];
// body
// }
// and let the existing 'for' loop code sort out the rest.
FName sizevar = "@size";
FName itvar = "@i";
auto block = new FxCompoundStatement(ScriptPosition);
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition);
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
block->Add(size);
block->Add(it);
auto cit = new FxLocalVariable(it, ScriptPosition);
auto csiz = new FxLocalVariable(size, ScriptPosition);
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
auto iit = new FxLocalVariable(it, ScriptPosition);
auto bump = new FxPreIncrDecr(iit, TK_Incr);
auto ait = new FxLocalVariable(it, ScriptPosition);
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
auto body = new FxCompoundStatement(ScriptPosition);
body->Add(assign);
body->Add(Code);
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
block->Add(forloop);
Array2 = Array = nullptr;
Code = nullptr;
delete this;
return castIt->Resolve(ctx);
return block->Resolve(ctx);
}
// Instead of writing a new code generator for this, convert this into
//
// int @size = array.Size();
// for(int @i = 0; @i < @size; @i++)
// {
// let var = array[i];
// body
// }
// and let the existing 'for' loop code sort out the rest.
FName sizevar = "@size";
FName itvar = "@i";
auto block = new FxCompoundStatement(ScriptPosition);
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition);
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
block->Add(size);
block->Add(it);
auto cit = new FxLocalVariable(it, ScriptPosition);
auto csiz = new FxLocalVariable(size, ScriptPosition);
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
auto iit = new FxLocalVariable(it, ScriptPosition);
auto bump = new FxPreIncrDecr(iit, TK_Incr);
auto ait = new FxLocalVariable(it, ScriptPosition);
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
auto body = new FxCompoundStatement(ScriptPosition);
body->Add(assign);
body->Add(Code);
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
block->Add(forloop);
Array2 = Array = nullptr;
Code = nullptr;
delete this;
return block->Resolve(ctx);
}
//==========================================================================
@ -11486,8 +11476,8 @@ FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
//
//==========================================================================
FxMapForEachLoop::FxMapForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_MapForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code)
FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code)
{
ValueType = TypeVoid;
if (MapExpr != nullptr) MapExpr->NeedResult = false;
@ -11497,7 +11487,7 @@ FxMapForEachLoop::FxMapForEachLoop(FName kv, FName vv, FxExpression* mapexpr, Fx
if (Code != nullptr) Code->NeedResult = false;
}
FxMapForEachLoop::~FxMapForEachLoop()
FxTwoArgForEachLoop::~FxTwoArgForEachLoop()
{
SAFE_DELETE(MapExpr);
SAFE_DELETE(MapExpr2);
@ -11506,7 +11496,12 @@ FxMapForEachLoop::~FxMapForEachLoop()
SAFE_DELETE(Code);
}
FxExpression *FxMapForEachLoop::Resolve(FCompileContext &ctx)
extern bool HasGameSpecificTwoArgForEachLoopTypeNames();
extern const char * GetGameSpecificTwoArgForEachLoopTypeNames();
extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(MapExpr, ctx);
@ -11516,21 +11511,24 @@ FxExpression *FxMapForEachLoop::Resolve(FCompileContext &ctx)
bool is_iterator = false;
if(MapExpr->ValueType->isObjectPointer() && (((PObjectPointer*)MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator))
if(IsGameSpecificTwoArgForEachLoop(this))
{
auto blockIt = new FxBlockIteratorForEachLoop(keyVarName, valueVarName, NAME_None, MapExpr, Code, ScriptPosition);
delete MapExpr2;
delete MapExpr3;
delete MapExpr4;
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
delete this;
return blockIt->Resolve(ctx);
return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx);
}
else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator())))
{
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s",MapExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
if(HasGameSpecificTwoArgForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
}
else if(valueVarName == NAME_None)
{
@ -11636,117 +11634,56 @@ FxExpression *FxMapForEachLoop::Resolve(FCompileContext &ctx)
//==========================================================================
//
// FxBlockIteratorForEachLoop
// FxThreeArgForEachLoop
//
//==========================================================================
FxBlockIteratorForEachLoop::FxBlockIteratorForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_BlockForEachLoop,pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code)
FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code)
{
ValueType = TypeVoid;
if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxBlockIteratorForEachLoop::~FxBlockIteratorForEachLoop()
FxThreeArgForEachLoop::~FxThreeArgForEachLoop()
{
SAFE_DELETE(BlockIteratorExpr);
SAFE_DELETE(Code);
}
FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx)
extern bool HasGameSpecificThreeArgForEachLoopTypeNames();
extern const char * GetGameSpecificThreeArgForEachLoopTypeNames();
extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(BlockIteratorExpr, ctx);
if(!(BlockIteratorExpr->ValueType->isObjectPointer()))
if(IsGameSpecificThreeArgForEachLoop(this))
{
ScriptPosition.Message(MSG_ERROR, "foreach( v, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else if(varVarName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach( v, p, f : b )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)BlockIteratorExpr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_BlockThingsIterator)
{
fieldName = "Thing";
}
else if(itType->TypeName == NAME_BlockLinesIterator)
{
fieldName = "CurLine";
return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx);
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( t, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
//put any non-game-specific typed for-each loops here
}
if(HasGameSpecificThreeArgForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
auto var = itType->FindSymbol(fieldName, false);
if(var && var->IsKindOf(RUNTIME_CLASS(PField)))
else
{
varType = static_cast<PField*>(var)->Type;
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported");
delete this;
return nullptr;
}
/*
{
Line|Actor var;
Vector3 pos;
int flags;
BlockLinesIterator|BlockThingsIterator @it = expr;
while(@it.Next())
{
var = @it.CurLine|@it.Thing;
pos = @it.position;
flags = @it.portalflags;
body
}
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varVarName, nullptr, 0, ScriptPosition));
if(posVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeVector3, posVarName, nullptr, 0, ScriptPosition));
}
if(flagsVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeSInt32, flagsVarName, nullptr, 0, ScriptPosition));
}
block->Add(new FxLocalVariableDeclaration(BlockIteratorExpr->ValueType, "@it", BlockIteratorExpr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
inner_block->Add(new FxAssign(new FxIdentifier(varVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), fieldName, ScriptPosition), true));
if(posVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(posVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "position", ScriptPosition), true));
}
if(flagsVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(flagsVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "portalflags", ScriptPosition), true));
}
inner_block->Add(Code);
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
BlockIteratorExpr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
//==========================================================================
@ -11755,104 +11692,51 @@ FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx)
//
//==========================================================================
FxCastForEachLoop::FxCastForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_BlockForEachLoop, pos), castClassName(cv), varVarName(vv), CastIteratorExpr(castiteartorexpr), Code(code)
FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos)
: FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code)
{
ValueType = TypeVoid;
if (CastIteratorExpr != nullptr) CastIteratorExpr->NeedResult = false;
if (Expr != nullptr) Expr->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxCastForEachLoop::~FxCastForEachLoop()
FxTypedForEachLoop::~FxTypedForEachLoop()
{
SAFE_DELETE(CastIteratorExpr);
SAFE_DELETE(Expr);
SAFE_DELETE(Code);
}
FxExpression *FxCastForEachLoop::Resolve(FCompileContext &ctx)
extern bool HasGameSpecificTypedForEachLoopTypeNames();
extern const char * GetGameSpecificTypedForEachLoopTypeNames();
extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(CastIteratorExpr, ctx);
SAFE_RESOLVE(Expr, ctx);
if(!(CastIteratorExpr->ValueType->isObjectPointer()))
if(IsGameSpecificTypedForEachLoop(this))
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",CastIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else if(varVarName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach(Type var : it )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)CastIteratorExpr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_ActorIterator)
{
fieldName = "Actor";
}
else if(itType->TypeName == NAME_ThinkerIterator)
{
fieldName = "Thinker";
return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx);
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",CastIteratorExpr->ValueType->DescriptiveName());
//put any non-game-specific typed for-each loops here
}
if(HasGameSpecificTypedForEachLoopTypeNames())
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be % but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
if(castClassName != NAME_None)
else
{
fieldName = castClassName;
}
PClass * varTypeClass = PClass::FindClass(fieldName);
varType = varTypeClass->VMType;
if(!varType)
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - could not find class '%s'",castClassName.GetChars());
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported");
delete this;
return nullptr;
}
varType = NewPointer(varType, false);
/*
{
CastType var;
ActorIterator|ThinkerIterator @it = expr;
while(var = CastType(@it.Next()))
body
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varVarName, nullptr, 0, ScriptPosition));
block->Add(new FxLocalVariableDeclaration(CastIteratorExpr->ValueType, "@it", CastIteratorExpr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
FxExpression * nextCallCast = new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition);
if(castClassName != NAME_None)
{
nextCallCast = new FxDynamicCast(varTypeClass, nextCallCast);
}
block->Add(new FxWhileLoop(new FxAssign(new FxIdentifier(varVarName, ScriptPosition), nextCallCast), Code, ScriptPosition));
CastIteratorExpr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
//==========================================================================

View file

@ -275,9 +275,9 @@ enum EFxType
EFX_DoWhileLoop,
EFX_ForLoop,
EFX_ForEachLoop,
EFX_MapForEachLoop,
EFX_BlockForEachLoop,
EFX_CastForEachLoop,
EFX_TwoArgForEachLoop,
EFX_ThreeArgForEachLoop,
EFX_TypedForEachLoop,
EFX_JumpStatement,
EFX_ReturnStatement,
EFX_ClassTypeCast,
@ -2073,6 +2073,7 @@ public:
class FxForEachLoop : public FxLoopStatement
{
public:
FName loopVarName;
FxExpression* Array;
FxExpression* Array2;
@ -2080,7 +2081,6 @@ class FxForEachLoop : public FxLoopStatement
FxExpression* Array4;
FxExpression* Code;
public:
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos);
~FxForEachLoop();
FxExpression* DoResolve(FCompileContext&);
@ -2088,12 +2088,13 @@ public:
//==========================================================================
//
// FxMapForEachLoop
// FxTwoArgForEachLoop
//
//==========================================================================
class FxMapForEachLoop : public FxExpression
class FxTwoArgForEachLoop : public FxExpression
{
public:
FName keyVarName;
FName valueVarName;
FxExpression* MapExpr;
@ -2102,50 +2103,49 @@ class FxMapForEachLoop : public FxExpression
FxExpression* MapExpr4;
FxExpression* Code;
public:
FxMapForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos);
~FxMapForEachLoop();
FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos);
~FxTwoArgForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxBlockIteratorForEachLoop
// FxThreeArgForEachLoop
//
//==========================================================================
class FxBlockIteratorForEachLoop : public FxExpression
class FxThreeArgForEachLoop : public FxExpression
{
public:
FName varVarName;
FName posVarName;
FName flagsVarName;
FxExpression* BlockIteratorExpr;
FxExpression* Code;
public:
FxBlockIteratorForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxBlockIteratorForEachLoop();
FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxThreeArgForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxCastForEachLoop
// FxTypedForEachLoop
//
//==========================================================================
class FxCastForEachLoop : public FxExpression
class FxTypedForEachLoop : public FxExpression
{
FName castClassName;
FName varVarName;
FxExpression* CastIteratorExpr;
public:
FName className;
FName varName;
FxExpression* Expr;
FxExpression* Code;
public:
FxCastForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxCastForEachLoop();
FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxTypedForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};

View file

@ -983,9 +983,9 @@ static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node)
out.Close();
}
static void PrintMapIterationStmt(FLispString &out, const ZCC_TreeNode *node)
static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_MapIterationStmt *)node;
auto inode = (ZCC_TwoArgIterationStmt *)node;
out.Break();
out.Open("map-iteration-stmt");
PrintVarName(out, inode->ItKey);
@ -998,9 +998,9 @@ static void PrintMapIterationStmt(FLispString &out, const ZCC_TreeNode *node)
out.Close();
}
static void PrintBlockIterationStmt(FLispString &out, const ZCC_TreeNode *node)
static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_BlockIterationStmt *)node;
auto inode = (ZCC_ThreeArgIterationStmt *)node;
out.Break();
out.Open("block-iteration-stmt");
PrintVarName(out, inode->ItVar);
@ -1015,16 +1015,16 @@ static void PrintBlockIterationStmt(FLispString &out, const ZCC_TreeNode *node)
out.Close();
}
static void PrintCastIterationStmt(FLispString &out, const ZCC_TreeNode *node)
static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_CastIterationStmt *)node;
auto inode = (ZCC_TypedIterationStmt *)node;
out.Break();
out.Open("cast-iteration-stmt");
PrintVarName(out, inode->ItCast);
PrintVarName(out, inode->ItType);
out.Break();
PrintVarName(out, inode->ItVar);
out.Break();
PrintNodes(out, inode->ItIterator);
PrintNodes(out, inode->ItExpr);
out.Break();
PrintNodes(out, inode->LoopStatement);
out.Close();
@ -1097,9 +1097,9 @@ static const NodePrinterFunc TreeNodePrinter[] =
PrintMixinDef,
PrintMixinStmt,
PrintArrayIterationStmt,
PrintMapIterationStmt,
PrintBlockIterationStmt,
PrintCastIterationStmt,
PrintTwoArgIterationStmt,
PrintThreeArgIterationStmt,
PrintTypedIterationStmt,
};
FString ZCC_PrintAST(const ZCC_TreeNode *root)

View file

@ -1956,9 +1956,9 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/
statement(X) ::= selection_statement(X).
statement(X) ::= iteration_statement(X).
statement(X) ::= array_iteration_statement(X).
statement(X) ::= map_iteration_statement(X).
statement(X) ::= block_iteration_statement(X).
statement(X) ::= cast_iteration_statement(X).
statement(X) ::= two_arg_iteration_statement(X).
statement(X) ::= three_arg_iteration_statement(X).
statement(X) ::= typed_iteration_statement(X).
statement(X) ::= jump_statement(X).
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ }
@ -2128,11 +2128,11 @@ array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr(
X = iter;
}
%type map_iteration_statement{ZCC_Statement *}
%type two_arg_iteration_statement{ZCC_Statement *}
map_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST).
two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(MapIterationStmt, iter, T);
NEW_AST_NODE(TwoArgIterationStmt, iter, T);
iter->ItKey = KEY;
iter->ItValue = VAL;
iter->ItMap = EX;
@ -2140,11 +2140,11 @@ map_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variab
X = iter;
}
%type block_iteration_statement{ZCC_Statement *}
%type three_arg_iteration_statement{ZCC_Statement *}
block_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST).
three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(BlockIterationStmt, iter, T);
NEW_AST_NODE(ThreeArgIterationStmt, iter, T);
iter->ItVar = VAR;
iter->ItPos = POS;
iter->ItFlags = FLAGS;
@ -2153,14 +2153,14 @@ block_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA vari
X = iter;
}
%type cast_iteration_statement{ZCC_Statement *}
%type typed_iteration_statement{ZCC_Statement *}
cast_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(CAST) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(CastIterationStmt, iter, T);
iter->ItCast = CAST;
NEW_AST_NODE(TypedIterationStmt, iter, T);
iter->ItType = TYPE;
iter->ItVar = VAR;
iter->ItIterator = EX;
iter->ItExpr = EX;
iter->LoopStatement = ST;
X = iter;
}

View file

@ -3395,9 +3395,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast);
}
case AST_MapIterationStmt:
case AST_TwoArgIterationStmt:
{
auto iter = static_cast<ZCC_MapIterationStmt*>(ast);
auto iter = static_cast<ZCC_TwoArgIterationStmt*>(ast);
auto key = iter->ItKey->Name;
auto var = iter->ItValue->Name;
FxExpression* const itMap = ConvertNode(iter->ItMap);
@ -3405,28 +3405,28 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
FxExpression* const itMap3 = ConvertNode(iter->ItMap);
FxExpression* const itMap4 = ConvertNode(iter->ItMap);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxMapForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast);
return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast);
}
case AST_BlockIterationStmt:
case AST_ThreeArgIterationStmt:
{
auto iter = static_cast<ZCC_BlockIterationStmt*>(ast);
auto iter = static_cast<ZCC_ThreeArgIterationStmt*>(ast);
auto var = iter->ItVar->Name;
auto pos = iter->ItPos->Name;
auto flags = iter->ItFlags->Name;
FxExpression* const itBlock = ConvertNode(iter->ItBlock);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxBlockIteratorForEachLoop(var, pos, flags, itBlock, body, *ast);
return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast);
}
case AST_CastIterationStmt:
case AST_TypedIterationStmt:
{
auto iter = static_cast<ZCC_CastIterationStmt*>(ast);
auto cls = iter->ItCast->Name;
auto iter = static_cast<ZCC_TypedIterationStmt*>(ast);
auto cls = iter->ItType->Name;
auto var = iter->ItVar->Name;
FxExpression* const itIterator = ConvertNode(iter->ItIterator);
FxExpression* const itExpr = ConvertNode(iter->ItExpr);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxCastForEachLoop(cls, var, itIterator, body, *ast);
return new FxTypedForEachLoop(cls, var, itExpr, body, *ast);
}
case AST_IterationStmt:

View file

@ -1177,11 +1177,11 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
break;
}
case AST_MapIterationStmt:
case AST_TwoArgIterationStmt:
{
TreeNodeDeepCopy_Start(MapIterationStmt);
TreeNodeDeepCopy_Start(TwoArgIterationStmt);
// ZCC_MapIterationStmt
// ZCC_TwoArgIterationStmt
copy->ItKey = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList));
copy->ItValue = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
@ -1190,6 +1190,33 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
break;
}
case AST_ThreeArgIterationStmt:
{
TreeNodeDeepCopy_Start(ThreeArgIterationStmt);
// ZCC_TwoArgIterationStmt
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
copy->ItPos = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList));
copy->ItFlags = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
copy->ItBlock = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList));
break;
}
case AST_TypedIterationStmt:
{
TreeNodeDeepCopy_Start(TypedIterationStmt);
// ZCC_TwoArgIterationStmt
copy->ItType = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList));
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
copy->ItExpr = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList));
break;
}
case AST_IfStmt:
{
TreeNodeDeepCopy_Start(IfStmt);

View file

@ -145,9 +145,9 @@ enum EZCCTreeNodeType
AST_MixinDef,
AST_MixinStmt,
AST_ArrayIterationStmt,
AST_MapIterationStmt,
AST_BlockIterationStmt,
AST_CastIterationStmt,
AST_TwoArgIterationStmt,
AST_ThreeArgIterationStmt,
AST_TypedIterationStmt,
NUM_AST_NODE_TYPES
};
@ -535,7 +535,7 @@ struct ZCC_ArrayIterationStmt : ZCC_Statement
ZCC_Statement* LoopStatement;
};
struct ZCC_MapIterationStmt : ZCC_Statement
struct ZCC_TwoArgIterationStmt : ZCC_Statement
{
ZCC_VarName* ItKey;
ZCC_VarName* ItValue;
@ -543,7 +543,7 @@ struct ZCC_MapIterationStmt : ZCC_Statement
ZCC_Statement* LoopStatement;
};
struct ZCC_BlockIterationStmt : ZCC_Statement
struct ZCC_ThreeArgIterationStmt : ZCC_Statement
{
ZCC_VarName* ItVar;
ZCC_VarName* ItPos;
@ -552,11 +552,11 @@ struct ZCC_BlockIterationStmt : ZCC_Statement
ZCC_Statement* LoopStatement;
};
struct ZCC_CastIterationStmt : ZCC_Statement
struct ZCC_TypedIterationStmt : ZCC_Statement
{
ZCC_VarName* ItCast;
ZCC_VarName* ItType;
ZCC_VarName* ItVar;
ZCC_Expression* ItIterator;
ZCC_Expression* ItExpr;
ZCC_Statement* LoopStatement;
};

View file

@ -972,3 +972,349 @@ void SetDoomCompileEnvironment()
compileEnvironment.CheckCustomGlobalFunctions = ResolveGlobalCustomFunction;
compileEnvironment.CustomBuiltinNew = "BuiltinNewDoom";
}
//==========================================================================
//
// FxCastForEachLoop
//
//==========================================================================
class FxCastForEachLoop : public FxTypedForEachLoop
{
public:
using FxTypedForEachLoop::FxTypedForEachLoop;
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
FxExpression *FxCastForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Expr, ctx);
if(varName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach(Type var : it )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)Expr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_ActorIterator)
{
fieldName = "Actor";
}
else if(itType->TypeName == NAME_ThinkerIterator)
{
fieldName = "Thinker";
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",Expr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
if(className != NAME_None)
{
fieldName = className;
}
PClass * varTypeClass = PClass::FindClass(fieldName);
varType = varTypeClass->VMType;
if(!varType)
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - could not find class '%s'",className.GetChars());
delete this;
return nullptr;
}
varType = NewPointer(varType, false);
/*
{
CastType var;
ActorIterator|ThinkerIterator @it = expr;
while(var = CastType(@it.Next()))
body
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varName, nullptr, 0, ScriptPosition));
block->Add(new FxLocalVariableDeclaration(Expr->ValueType, "@it", Expr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
FxExpression * nextCallCast = new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition);
if(className != NAME_None)
{
nextCallCast = new FxDynamicCast(varTypeClass, nextCallCast);
}
block->Add(new FxWhileLoop(new FxAssign(new FxIdentifier(varName, ScriptPosition), nextCallCast), Code, ScriptPosition));
Expr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
//==========================================================================
//
// FxBlockIteratorForEachLoop
//
//==========================================================================
class FxBlockIteratorForEachLoop : public FxThreeArgForEachLoop
{
public:
using FxThreeArgForEachLoop::FxThreeArgForEachLoop;
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(BlockIteratorExpr, ctx);
if(!(BlockIteratorExpr->ValueType->isObjectPointer()))
{
ScriptPosition.Message(MSG_ERROR, "foreach( v, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else if(varVarName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach( v, p, f : b )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)BlockIteratorExpr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_BlockThingsIterator)
{
fieldName = "Thing";
}
else if(itType->TypeName == NAME_BlockLinesIterator)
{
fieldName = "CurLine";
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( t, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
auto var = itType->FindSymbol(fieldName, false);
if(var && var->IsKindOf(RUNTIME_CLASS(PField)))
{
varType = static_cast<PField*>(var)->Type;
}
/*
{
Line|Actor var;
Vector3 pos;
int flags;
BlockLinesIterator|BlockThingsIterator @it = expr;
while(@it.Next())
{
var = @it.CurLine|@it.Thing;
pos = @it.position;
flags = @it.portalflags;
body
}
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varVarName, nullptr, 0, ScriptPosition));
if(posVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeVector3, posVarName, nullptr, 0, ScriptPosition));
}
if(flagsVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeSInt32, flagsVarName, nullptr, 0, ScriptPosition));
}
block->Add(new FxLocalVariableDeclaration(BlockIteratorExpr->ValueType, "@it", BlockIteratorExpr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
inner_block->Add(new FxAssign(new FxIdentifier(varVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), fieldName, ScriptPosition), true));
if(posVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(posVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "position", ScriptPosition), true));
}
if(flagsVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(flagsVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "portalflags", ScriptPosition), true));
}
inner_block->Add(Code);
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
BlockIteratorExpr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
bool IsGameSpecificForEachLoop(FxForEachLoop * loop)
{
auto * vt = loop->Array->ValueType;
return (vt->isObjectPointer() && (
((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockThingsIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator
));
}
FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop * loop)
{
FName cname = ((PObjectPointer*)loop->Array->ValueType)->PointedClass()->TypeName;
assert(loop->Array->ValueType->isObjectPointer());
if(cname == NAME_BlockLinesIterator || cname == NAME_BlockThingsIterator)
{
auto blockIt = new FxBlockIteratorForEachLoop(loop->loopVarName, NAME_None, NAME_None, loop->Array, loop->Code, loop->ScriptPosition);
loop->Array = loop->Code = nullptr;
delete loop;
return blockIt;
}
else if(cname == NAME_ActorIterator || cname == NAME_ThinkerIterator)
{
auto castIt = new FxCastForEachLoop(NAME_None, loop->loopVarName, loop->Array, loop->Code, loop->ScriptPosition);
loop->Array = loop->Code = nullptr;
delete loop;
return castIt;
}
else
{
delete loop;
return nullptr;
}
}
bool HasGameSpecificTwoArgForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificTwoArgForEachLoopTypeNames()
{
return "a BlockLinesIterator, a BlockThingsIterator,";
}
bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop)
{
return (loop->MapExpr->ValueType->isObjectPointer()
&& (((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator));
}
FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop)
{
assert(loop->MapExpr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator);
auto blockIt = new FxBlockIteratorForEachLoop(loop->keyVarName, loop->valueVarName, NAME_None, loop->MapExpr, loop->Code, loop->ScriptPosition);
loop->MapExpr = loop->Code = nullptr;
delete loop;
return blockIt;
}
bool HasGameSpecificThreeArgForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificThreeArgForEachLoopTypeNames()
{
return "a BlockLinesIterator or a BlockThingsIterator";
}
bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop)
{
return (loop->BlockIteratorExpr->ValueType->isObjectPointer()
&& (((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator));
}
FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop)
{
assert(loop->BlockIteratorExpr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator);
auto blockIt = new FxBlockIteratorForEachLoop(loop->varVarName, loop->posVarName, loop->flagsVarName, loop->BlockIteratorExpr, loop->Code, loop->ScriptPosition);
loop->BlockIteratorExpr = loop->Code = nullptr;
delete loop;
return blockIt;
}
bool HasGameSpecificTypedForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificTypedForEachLoopTypeNames()
{
return "an ActorIterator or a ThinkerIterator";
}
bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop)
{
auto * vt = loop->Expr->ValueType;
return (vt->isObjectPointer() && (
((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator
));
}
FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop)
{
assert(loop->Expr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ActorIterator || ((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ThinkerIterator);
FxExpression * castIt = new FxCastForEachLoop(loop->className, loop->varName, loop->Expr, loop->Code, loop->ScriptPosition);
loop->Expr = loop->Code = nullptr;
delete loop;
return castIt;
}