From f5507a7373ac12e6b54eda7b78d50059b1f57dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 15 Oct 2023 16:19:55 -0300 Subject: [PATCH] add foreach(a/l/a,p/l,p/a,p,f/l,p,f : blocklinesiterator/blockthingsiterator) --- src/common/engine/namedef.h | 2 + src/common/scripting/backend/codegen.cpp | 142 +++++++++++++++++- src/common/scripting/backend/codegen.h | 22 +++ src/common/scripting/frontend/ast.cpp | 18 +++ src/common/scripting/frontend/zcc-parse.lemon | 14 ++ src/common/scripting/frontend/zcc_compile.cpp | 11 ++ src/common/scripting/frontend/zcc_parser.h | 10 ++ 7 files changed, 216 insertions(+), 3 deletions(-) diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index 116765dc1..0c420b805 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -135,6 +135,8 @@ xx(FVector3) xx(FVector4) xx(FQuat) xx(let) +xx(BlockThingsIterator) +xx(BlockLinesIterator) xx(Min) xx(Max) diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index d98053736..1c1e0bcfc 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -11417,6 +11417,16 @@ FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx) 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)) + { + 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); + } // Instead of writing a new code generator for this, convert this into // @@ -11495,14 +11505,24 @@ FxExpression *FxMapForEachLoop::Resolve(FCompileContext &ctx) SAFE_RESOLVE(MapExpr4, ctx); bool is_iterator = false; - - if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator()))) + + if(MapExpr->ValueType->isObjectPointer() && (((PObjectPointer*)MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator)) + { + 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); + } + 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(valueVarName == NAME_None) + else if(valueVarName == NAME_None) { ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )"); delete this; @@ -11603,6 +11623,122 @@ FxExpression *FxMapForEachLoop::Resolve(FCompileContext &ctx) } } + +//========================================================================== +// +// FxBlockIteratorForEachLoop +// +//========================================================================== + +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) +{ + ValueType = TypeVoid; + if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxBlockIteratorForEachLoop::~FxBlockIteratorForEachLoop() +{ + SAFE_DELETE(BlockIteratorExpr); + SAFE_DELETE(Code); +} + +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); +} + //========================================================================== // // FxJumpStatement diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index ac86c5013..6b4a349d2 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -276,6 +276,7 @@ enum EFxType EFX_ForLoop, EFX_ForEachLoop, EFX_MapForEachLoop, + EFX_BlockForEachLoop, EFX_JumpStatement, EFX_ReturnStatement, EFX_ClassTypeCast, @@ -2107,6 +2108,27 @@ public: //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself }; +//========================================================================== +// +// FxBlockIteratorForEachLoop +// +//========================================================================== + +class FxBlockIteratorForEachLoop : public FxExpression +{ + 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(); + FxExpression *Resolve(FCompileContext&); + //ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself +}; + //========================================================================== // // FxJumpStatement diff --git a/src/common/scripting/frontend/ast.cpp b/src/common/scripting/frontend/ast.cpp index d190f9c5e..1c947cf46 100644 --- a/src/common/scripting/frontend/ast.cpp +++ b/src/common/scripting/frontend/ast.cpp @@ -998,6 +998,23 @@ static void PrintMapIterationStmt(FLispString &out, const ZCC_TreeNode *node) out.Close(); } +static void PrintBlockIterationStmt(FLispString &out, const ZCC_TreeNode *node) +{ + auto inode = (ZCC_BlockIterationStmt *)node; + out.Break(); + out.Open("block-iteration-stmt"); + PrintVarName(out, inode->ItVar); + out.Break(); + PrintVarName(out, inode->ItPos); + out.Break(); + PrintVarName(out, inode->ItFlags); + out.Break(); + PrintNodes(out, inode->ItBlock); + out.Break(); + PrintNodes(out, inode->LoopStatement); + out.Close(); +} + static const NodePrinterFunc TreeNodePrinter[] = { PrintIdentifier, @@ -1066,6 +1083,7 @@ static const NodePrinterFunc TreeNodePrinter[] = PrintMixinStmt, PrintArrayIterationStmt, PrintMapIterationStmt, + PrintBlockIterationStmt, }; 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 c708f325d..1dcdd1f72 100644 --- a/src/common/scripting/frontend/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -1957,6 +1957,7 @@ 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) ::= 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*/ } @@ -2138,6 +2139,19 @@ map_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variab X = iter; } +%type block_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). +{ + NEW_AST_NODE(BlockIterationStmt, iter, T); + iter->ItVar = VAR; + iter->ItPos = POS; + iter->ItFlags = FLAGS; + iter->ItBlock = EX; + iter->LoopStatement = ST; + X = iter; +} + while_or_until(X) ::= WHILE(T). { X.Int = ZCC_WHILE; diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp index 8eac47a11..b17687d93 100644 --- a/src/common/scripting/frontend/zcc_compile.cpp +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -3408,6 +3408,17 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute) return new FxMapForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast); } + case AST_BlockIterationStmt: + { + 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); + } + case AST_IterationStmt: { auto iter = static_cast(ast); diff --git a/src/common/scripting/frontend/zcc_parser.h b/src/common/scripting/frontend/zcc_parser.h index 446d0f8b4..0cdbb381c 100644 --- a/src/common/scripting/frontend/zcc_parser.h +++ b/src/common/scripting/frontend/zcc_parser.h @@ -146,6 +146,7 @@ enum EZCCTreeNodeType AST_MixinStmt, AST_ArrayIterationStmt, AST_MapIterationStmt, + AST_BlockIterationStmt, NUM_AST_NODE_TYPES }; @@ -541,6 +542,15 @@ struct ZCC_MapIterationStmt : ZCC_Statement ZCC_Statement* LoopStatement; }; +struct ZCC_BlockIterationStmt : ZCC_Statement +{ + ZCC_VarName* ItVar; + ZCC_VarName* ItPos; + ZCC_VarName* ItFlags; + ZCC_Expression* ItBlock; + ZCC_Statement* LoopStatement; +}; + struct ZCC_IfStmt : ZCC_Statement { ZCC_Expression *Condition;