mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-13 22:42:07 +00:00
add foreach(a/type a : thinkeriterator/actoriterator)
This commit is contained in:
parent
f5507a7373
commit
71999e7cf6
7 changed files with 187 additions and 0 deletions
|
@ -137,6 +137,8 @@ xx(FQuat)
|
|||
xx(let)
|
||||
xx(BlockThingsIterator)
|
||||
xx(BlockLinesIterator)
|
||||
xx(ActorIterator)
|
||||
xx(ThinkerIterator)
|
||||
|
||||
xx(Min)
|
||||
xx(Max)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue