mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-12 23:26:02 +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);
|
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);
|
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
|
// FxAssignSelf
|
||||||
|
|
|
@ -816,6 +816,15 @@ static void PrintAssignStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||||
out.Close();
|
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)
|
static void PrintLocalVarStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||||
{
|
{
|
||||||
ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node;
|
ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node;
|
||||||
|
@ -989,6 +998,7 @@ static const NodePrinterFunc TreeNodePrinter[] =
|
||||||
PrintSwitchStmt,
|
PrintSwitchStmt,
|
||||||
PrintCaseStmt,
|
PrintCaseStmt,
|
||||||
PrintAssignStmt,
|
PrintAssignStmt,
|
||||||
|
PrintAssignDeclStmt,
|
||||||
PrintLocalVarStmt,
|
PrintLocalVarStmt,
|
||||||
PrintFuncParamDecl,
|
PrintFuncParamDecl,
|
||||||
PrintConstantDef,
|
PrintConstantDef,
|
||||||
|
|
|
@ -1840,6 +1840,7 @@ statement(X) ::= iteration_statement(X).
|
||||||
statement(X) ::= array_iteration_statement(X).
|
statement(X) ::= array_iteration_statement(X).
|
||||||
statement(X) ::= jump_statement(X).
|
statement(X) ::= jump_statement(X).
|
||||||
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
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) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||||
statement(X) ::= error SEMICOLON. { X = NULL; }
|
statement(X) ::= error SEMICOLON. { X = NULL; }
|
||||||
statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
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;
|
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" -----*/
|
/*----- Local Variable Definition "Statements" -----*/
|
||||||
|
|
||||||
%type local_var{ZCC_LocalVarStmt *}
|
%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);
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1195,6 +1195,18 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
|
||||||
break;
|
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:
|
case AST_LocalVarStmt:
|
||||||
{
|
{
|
||||||
TreeNodeDeepCopy_Start(LocalVarStmt);
|
TreeNodeDeepCopy_Start(LocalVarStmt);
|
||||||
|
|
|
@ -122,6 +122,7 @@ enum EZCCTreeNodeType
|
||||||
AST_SwitchStmt,
|
AST_SwitchStmt,
|
||||||
AST_CaseStmt,
|
AST_CaseStmt,
|
||||||
AST_AssignStmt,
|
AST_AssignStmt,
|
||||||
|
AST_AssignDeclStmt,
|
||||||
AST_LocalVarStmt,
|
AST_LocalVarStmt,
|
||||||
AST_FuncParamDecl,
|
AST_FuncParamDecl,
|
||||||
AST_ConstantDef,
|
AST_ConstantDef,
|
||||||
|
@ -533,6 +534,13 @@ struct ZCC_AssignStmt : ZCC_Statement
|
||||||
int AssignOp;
|
int AssignOp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_AssignDeclStmt : ZCC_Statement
|
||||||
|
{
|
||||||
|
ZCC_Identifier *Dests;
|
||||||
|
ZCC_Expression *Sources;
|
||||||
|
int AssignOp;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_LocalVarStmt : ZCC_Statement
|
struct ZCC_LocalVarStmt : ZCC_Statement
|
||||||
{
|
{
|
||||||
ZCC_Type *Type;
|
ZCC_Type *Type;
|
||||||
|
|
Loading…
Reference in a new issue