add foreach(a/type a : thinkeriterator/actoriterator)

This commit is contained in:
Ricardo Luís Vaz Silva 2023-10-15 17:15:52 -03:00 committed by Rachael Alexanderson
parent f5507a7373
commit 71999e7cf6
7 changed files with 187 additions and 0 deletions

View file

@ -137,6 +137,8 @@ xx(FQuat)
xx(let)
xx(BlockThingsIterator)
xx(BlockLinesIterator)
xx(ActorIterator)
xx(ThinkerIterator)
xx(Min)
xx(Max)

View file

@ -11427,6 +11427,16 @@ FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
delete this;
return blockIt->Resolve(ctx);
}
else if(Array->ValueType->isObjectPointer() && (((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_ActorIterator || ((PObjectPointer*)Array->ValueType)->PointedClass()->TypeName == NAME_ThinkerIterator))
{
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
//
@ -11739,6 +11749,112 @@ FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx)
return block->Resolve(ctx);
}
//==========================================================================
//
// FxCastForEachLoop
//
//==========================================================================
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)
{
ValueType = TypeVoid;
if (CastIteratorExpr != nullptr) CastIteratorExpr->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxCastForEachLoop::~FxCastForEachLoop()
{
SAFE_DELETE(CastIteratorExpr);
SAFE_DELETE(Code);
}
FxExpression *FxCastForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(CastIteratorExpr, ctx);
if(!(CastIteratorExpr->ValueType->isObjectPointer()))
{
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";
}
else
{
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;
}
if(castClassName != NAME_None)
{
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());
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);
}
//==========================================================================
//
// FxJumpStatement

View file

@ -277,6 +277,7 @@ enum EFxType
EFX_ForEachLoop,
EFX_MapForEachLoop,
EFX_BlockForEachLoop,
EFX_CastForEachLoop,
EFX_JumpStatement,
EFX_ReturnStatement,
EFX_ClassTypeCast,
@ -2129,6 +2130,26 @@ public:
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxCastForEachLoop
//
//==========================================================================
class FxCastForEachLoop : public FxExpression
{
FName castClassName;
FName varVarName;
FxExpression* CastIteratorExpr;
FxExpression* Code;
public:
FxCastForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
~FxCastForEachLoop();
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
//==========================================================================
//
// FxJumpStatement

View file

@ -1015,6 +1015,21 @@ static void PrintBlockIterationStmt(FLispString &out, const ZCC_TreeNode *node)
out.Close();
}
static void PrintCastIterationStmt(FLispString &out, const ZCC_TreeNode *node)
{
auto inode = (ZCC_CastIterationStmt *)node;
out.Break();
out.Open("cast-iteration-stmt");
PrintVarName(out, inode->ItCast);
out.Break();
PrintVarName(out, inode->ItVar);
out.Break();
PrintNodes(out, inode->ItIterator);
out.Break();
PrintNodes(out, inode->LoopStatement);
out.Close();
}
static const NodePrinterFunc TreeNodePrinter[] =
{
PrintIdentifier,
@ -1084,6 +1099,7 @@ static const NodePrinterFunc TreeNodePrinter[] =
PrintArrayIterationStmt,
PrintMapIterationStmt,
PrintBlockIterationStmt,
PrintCastIterationStmt,
};
FString ZCC_PrintAST(const ZCC_TreeNode *root)

View file

@ -1958,6 +1958,7 @@ 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) ::= 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*/ }
@ -2152,6 +2153,18 @@ block_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA vari
X = iter;
}
%type cast_iteration_statement{ZCC_Statement *}
cast_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(CAST) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(CastIterationStmt, iter, T);
iter->ItCast = CAST;
iter->ItVar = VAR;
iter->ItIterator = EX;
iter->LoopStatement = ST;
X = iter;
}
while_or_until(X) ::= WHILE(T).
{
X.Int = ZCC_WHILE;

View file

@ -3419,6 +3419,16 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
return new FxBlockIteratorForEachLoop(var, pos, flags, itBlock, body, *ast);
}
case AST_CastIterationStmt:
{
auto iter = static_cast<ZCC_CastIterationStmt*>(ast);
auto cls = iter->ItCast->Name;
auto var = iter->ItVar->Name;
FxExpression* const itIterator = ConvertNode(iter->ItIterator);
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
return new FxCastForEachLoop(cls, var, itIterator, body, *ast);
}
case AST_IterationStmt:
{
auto iter = static_cast<ZCC_IterationStmt *>(ast);

View file

@ -147,6 +147,7 @@ enum EZCCTreeNodeType
AST_ArrayIterationStmt,
AST_MapIterationStmt,
AST_BlockIterationStmt,
AST_CastIterationStmt,
NUM_AST_NODE_TYPES
};
@ -551,6 +552,14 @@ struct ZCC_BlockIterationStmt : ZCC_Statement
ZCC_Statement* LoopStatement;
};
struct ZCC_CastIterationStmt : ZCC_Statement
{
ZCC_VarName* ItCast;
ZCC_VarName* ItVar;
ZCC_Expression* ItIterator;
ZCC_Statement* LoopStatement;
};
struct ZCC_IfStmt : ZCC_Statement
{
ZCC_Expression *Condition;