add foreach(a/l/a,p/l,p/a,p,f/l,p,f : blocklinesiterator/blockthingsiterator)

This commit is contained in:
Ricardo Luís Vaz Silva 2023-10-15 16:19:55 -03:00 committed by Rachael Alexanderson
parent 5cb0e3bc5b
commit f5507a7373
7 changed files with 216 additions and 3 deletions

View file

@ -135,6 +135,8 @@ xx(FVector3)
xx(FVector4)
xx(FQuat)
xx(let)
xx(BlockThingsIterator)
xx(BlockLinesIterator)
xx(Min)
xx(Max)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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;