diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index d161fa01494..84f7e76b4b5 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -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; - delete this; - return castIt->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); - // 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. + 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)); - FName sizevar = "@size"; - FName itvar = "@i"; + auto iit = new FxLocalVariable(it, ScriptPosition); + auto bump = new FxPreIncrDecr(iit, TK_Incr); - 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); + 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; + return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx); } - else if(varVarName == NAME_None) + else { - ScriptPosition.Message(MSG_ERROR, "missing var for foreach( v, p, f : b )"); - delete this; - return nullptr; + //put any non-game-specific typed for-each loops here } - PType * varType = nullptr; - PClass * itType = ((PObjectPointer*)BlockIteratorExpr->ValueType)->PointedClass(); - - FName fieldName = NAME_None; - - if(itType->TypeName == NAME_BlockThingsIterator) + if(HasGameSpecificThreeArgForEachLoopTypeNames()) { - fieldName = "Thing"; - } - else if(itType->TypeName == NAME_BlockLinesIterator) - { - fieldName = "CurLine"; + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName()); + delete this; + return nullptr; } 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()); + ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported"); delete this; return nullptr; } - - auto var = itType->FindSymbol(fieldName, false); - if(var && var->IsKindOf(RUNTIME_CLASS(PField))) - { - varType = static_cast(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); } //========================================================================== @@ -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; + return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx); } - else if(varVarName == NAME_None) + else { - ScriptPosition.Message(MSG_ERROR, "missing var for foreach(Type var : it )"); - delete this; - return nullptr; + //put any non-game-specific typed for-each loops here } - 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) + if(HasGameSpecificTypedForEachLoopTypeNames()) { - fieldName = "Thinker"; - } - else - { - ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",CastIteratorExpr->ValueType->DescriptiveName()); + 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) - { - fieldName = castClassName; - } - - PClass * varTypeClass = PClass::FindClass(fieldName); - varType = varTypeClass->VMType; - - if(!varType) + else { - 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); } //========================================================================== diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index fc05ccbe2cc..1b51eb1512b 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -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 @@ class FxForLoop : public FxLoopStatement 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 @@ class FxForEachLoop : public FxLoopStatement //========================================================================== // -// 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 }; diff --git a/src/common/scripting/frontend/ast.cpp b/src/common/scripting/frontend/ast.cpp index 1fc73905174..ba91077af05 100644 --- a/src/common/scripting/frontend/ast.cpp +++ b/src/common/scripting/frontend/ast.cpp @@ -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) diff --git a/src/common/scripting/frontend/zcc-parse.lemon b/src/common/scripting/frontend/zcc-parse.lemon index 25e47f63b62..199771949d3 100644 --- a/src/common/scripting/frontend/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -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; } diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp index bf2d0a4ce29..4c3f2bc383f 100644 --- a/src/common/scripting/frontend/zcc_compile.cpp +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -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(ast); + auto iter = static_cast(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(ast); + auto iter = static_cast(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(ast); - auto cls = iter->ItCast->Name; + auto iter = static_cast(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: diff --git a/src/common/scripting/frontend/zcc_parser.cpp b/src/common/scripting/frontend/zcc_parser.cpp index 02f56d232b6..1b7e846fd9f 100644 --- a/src/common/scripting/frontend/zcc_parser.cpp +++ b/src/common/scripting/frontend/zcc_parser.cpp @@ -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(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList)); copy->ItValue = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList)); copy->LoopStatement = static_cast(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(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->ItPos = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList)); + copy->ItFlags = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItBlock = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList)); + + break; + } + + case AST_TypedIterationStmt: + { + TreeNodeDeepCopy_Start(TypedIterationStmt); + + // ZCC_TwoArgIterationStmt + copy->ItType = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList)); + copy->ItVar = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList)); + copy->LoopStatement = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList)); + copy->ItExpr = static_cast(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList)); + + break; + } + case AST_IfStmt: { TreeNodeDeepCopy_Start(IfStmt); diff --git a/src/common/scripting/frontend/zcc_parser.h b/src/common/scripting/frontend/zcc_parser.h index faf1e3597aa..d0b6264da5d 100644 --- a/src/common/scripting/frontend/zcc_parser.h +++ b/src/common/scripting/frontend/zcc_parser.h @@ -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; }; diff --git a/src/scripting/backend/codegen_doom.cpp b/src/scripting/backend/codegen_doom.cpp index 189cf5047b9..5412cbb8ea1 100644 --- a/src/scripting/backend/codegen_doom.cpp +++ b/src/scripting/backend/codegen_doom.cpp @@ -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(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; +} \ No newline at end of file