mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-01 22:30:48 +00:00
Multi-Assign Declarations
This commit is contained in:
parent
7b9a36c8fd
commit
c8fe074041
7 changed files with 144 additions and 0 deletions
|
@ -2718,6 +2718,75 @@ ExpEmit FxMultiAssign::Emit(VMFunctionBuilder *build)
|
|||
return LocalVarContainer->Emit(build);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxMultiAssignDecl::FxMultiAssignDecl(FArgumentList &base, FxExpression *right, const FScriptPosition &pos)
|
||||
:FxExpression(EFX_MultiAssign, pos)
|
||||
{
|
||||
Base = std::move(base);
|
||||
Right = right;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxMultiAssignDecl::~FxMultiAssignDecl()
|
||||
{
|
||||
SAFE_DELETE(Right);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxMultiAssignDecl::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Right, ctx);
|
||||
if (Right->ExprType != EFX_VMFunctionCall)
|
||||
{
|
||||
Right->ScriptPosition.Message(MSG_ERROR, "Function call expected on right side of multi-assigment");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
auto VMRight = static_cast<FxVMFunctionCall *>(Right);
|
||||
auto rets = VMRight->GetReturnTypes();
|
||||
if (Base.Size() == 1)
|
||||
{
|
||||
Right->ScriptPosition.Message(MSG_ERROR, "Multi-assignment with only one element in function %s", VMRight->Function->SymbolName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
if (rets.Size() < Base.Size())
|
||||
{
|
||||
Right->ScriptPosition.Message(MSG_ERROR, "Insufficient returns in function %s", VMRight->Function->SymbolName.GetChars());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
FxSequence * DeclAndAssign = new FxSequence(ScriptPosition);
|
||||
const unsigned int n = Base.Size();
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
assert(Base[i]->ExprType == EFX_Identifier);
|
||||
DeclAndAssign->Add(new FxLocalVariableDeclaration(rets[i], ((FxIdentifier*)Base[i])->Identifier, nullptr, 0, Base[i]->ScriptPosition));
|
||||
}
|
||||
DeclAndAssign->Add(new FxMultiAssign(Base, Right, ScriptPosition));
|
||||
Right = nullptr;
|
||||
delete this;
|
||||
return DeclAndAssign->Resolve(ctx);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -904,6 +904,17 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
class FxMultiAssignDecl : public FxExpression
|
||||
{
|
||||
FArgumentList Base;
|
||||
FxExpression *Right;
|
||||
public:
|
||||
FxMultiAssignDecl(FArgumentList &base, FxExpression *right, const FScriptPosition &pos);
|
||||
~FxMultiAssignDecl();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed into Declarations + FxMultiAssign , so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxAssignSelf
|
||||
|
|
|
@ -816,6 +816,15 @@ static void PrintAssignStmt(FLispString &out, const ZCC_TreeNode *node)
|
|||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintAssignDeclStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
ZCC_AssignDeclStmt *snode = (ZCC_AssignDeclStmt *)node;
|
||||
out.Open("assign-stmt-decl");
|
||||
PrintNodes(out, snode->Dests);
|
||||
PrintNodes(out, snode->Sources);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintLocalVarStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node;
|
||||
|
@ -989,6 +998,7 @@ static const NodePrinterFunc TreeNodePrinter[] =
|
|||
PrintSwitchStmt,
|
||||
PrintCaseStmt,
|
||||
PrintAssignStmt,
|
||||
PrintAssignDeclStmt,
|
||||
PrintLocalVarStmt,
|
||||
PrintFuncParamDecl,
|
||||
PrintConstantDef,
|
||||
|
|
|
@ -1840,6 +1840,7 @@ statement(X) ::= iteration_statement(X).
|
|||
statement(X) ::= array_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*/ }
|
||||
statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||
statement(X) ::= error SEMICOLON. { X = NULL; }
|
||||
statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||
|
@ -2098,6 +2099,17 @@ assign_statement(X) ::= LBRACKET expr_list(A) RBRACKET EQ expr(B). [EQ]
|
|||
X = stmt;
|
||||
}
|
||||
|
||||
%type assign_decl_statement{ZCC_AssignDeclStmt *}
|
||||
|
||||
assign_decl_statement(X) ::= LET LBRACKET identifier_list(A) RBRACKET EQ expr(B). [EQ]
|
||||
{
|
||||
NEW_AST_NODE(AssignDeclStmt,stmt,A);
|
||||
stmt->AssignOp = ZCC_EQ;
|
||||
stmt->Dests = A;
|
||||
stmt->Sources = B;
|
||||
X = stmt;
|
||||
}
|
||||
|
||||
/*----- Local Variable Definition "Statements" -----*/
|
||||
|
||||
%type local_var{ZCC_LocalVarStmt *}
|
||||
|
|
|
@ -3350,6 +3350,28 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast);
|
||||
}
|
||||
|
||||
case AST_AssignDeclStmt:
|
||||
{
|
||||
auto ass = static_cast<ZCC_AssignDeclStmt *>(ast);
|
||||
FArgumentList args;
|
||||
{
|
||||
ZCC_TreeNode *n = ass->Dests;
|
||||
if(n) do
|
||||
{
|
||||
args.Push(new FxIdentifier(static_cast<ZCC_Identifier*>(n)->Id,*n));
|
||||
n = n->SiblingNext;
|
||||
} while(n != ass->Dests);
|
||||
}
|
||||
assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else
|
||||
if (ass->Sources->NodeType != AST_ExprFuncCall)
|
||||
{
|
||||
// don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable.
|
||||
Error(ass, "Right side of multi-assignment must be a function call");
|
||||
return new FxNop(*ast); // allow compiler to continue looking for errors.
|
||||
}
|
||||
return new FxMultiAssignDecl(args, ConvertNode(ass->Sources), *ast);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1195,6 +1195,18 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
|
|||
break;
|
||||
}
|
||||
|
||||
case AST_AssignDeclStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(AssignDeclStmt);
|
||||
|
||||
// ZCC_AssignDeclStmt
|
||||
copy->Dests = static_cast<ZCC_Identifier *>(TreeNodeDeepCopy_Internal(ast, origCasted->Dests, true, copiedNodesList));
|
||||
copy->Sources = static_cast<ZCC_Expression *>(TreeNodeDeepCopy_Internal(ast, origCasted->Sources, true, copiedNodesList));
|
||||
copy->AssignOp = origCasted->AssignOp;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_LocalVarStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(LocalVarStmt);
|
||||
|
|
|
@ -122,6 +122,7 @@ enum EZCCTreeNodeType
|
|||
AST_SwitchStmt,
|
||||
AST_CaseStmt,
|
||||
AST_AssignStmt,
|
||||
AST_AssignDeclStmt,
|
||||
AST_LocalVarStmt,
|
||||
AST_FuncParamDecl,
|
||||
AST_ConstantDef,
|
||||
|
@ -533,6 +534,13 @@ struct ZCC_AssignStmt : ZCC_Statement
|
|||
int AssignOp;
|
||||
};
|
||||
|
||||
struct ZCC_AssignDeclStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Identifier *Dests;
|
||||
ZCC_Expression *Sources;
|
||||
int AssignOp;
|
||||
};
|
||||
|
||||
struct ZCC_LocalVarStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Type *Type;
|
||||
|
|
Loading…
Reference in a new issue