Multi-Assign Declarations

This commit is contained in:
Ricardo Luís Vaz Silva 2022-12-20 10:44:20 -03:00 committed by Christoph Oelckers
parent 7b9a36c8fd
commit c8fe074041
7 changed files with 144 additions and 0 deletions

View file

@ -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);
}
//==========================================================================
//
//

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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