mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-13 22:42:07 +00:00
add foreach(a/l/a,p/l,p/a,p,f/l,p,f : blocklinesiterator/blockthingsiterator)
This commit is contained in:
parent
5cb0e3bc5b
commit
f5507a7373
7 changed files with 216 additions and 3 deletions
|
@ -135,6 +135,8 @@ xx(FVector3)
|
|||
xx(FVector4)
|
||||
xx(FQuat)
|
||||
xx(let)
|
||||
xx(BlockThingsIterator)
|
||||
xx(BlockLinesIterator)
|
||||
|
||||
xx(Min)
|
||||
xx(Max)
|
||||
|
|
|
@ -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<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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxJumpStatement
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ZCC_BlockIterationStmt*>(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<ZCC_IterationStmt *>(ast);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue