From a0ce8f298849818b5f24734c94ec075d8da0955f Mon Sep 17 00:00:00 2001 From: Chronos Ouroboros Date: Fri, 4 Jan 2019 20:54:03 -0200 Subject: [PATCH] Implemented compound initializers for arrays. --- src/scripting/backend/codegen.cpp | 160 +++++++++++++++++++++++++- src/scripting/backend/codegen.h | 21 ++++ src/scripting/zscript/zcc_compile.cpp | 11 +- 3 files changed, 186 insertions(+), 6 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index db87134ddd..09e8b55d1f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -11158,7 +11158,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) { auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); StackOffset = sfunc->AllocExtraStack(ValueType); - // Todo: Process the compound initializer once implemented. + if (Init != nullptr) { ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); @@ -11400,3 +11400,161 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) } return ExpEmit(); } + +FxLocalArrayDeclaration::FxLocalArrayDeclaration(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos) + : FxLocalVariableDeclaration(NewArray(type, args.Size()), name, nullptr, 0, pos) +{ + ElementType = type; + ExprType = EFX_LocalArrayDeclaration; + values = std::move(args); +} + +FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + for (unsigned int i = 0; i < values.Size(); i++) + { + auto v = values[i]->Resolve(ctx); + if (v == nullptr) + { + delete this; + return nullptr; + } + values[i] = v; + } + + if (ctx.Block == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Variable declaration outside compound statement"); + delete this; + return nullptr; + } + if (ValueType->RegType == REGT_NIL && ValueType != TypeAuto) + { + auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); + StackOffset = sfunc->AllocExtraStack(ValueType); + + if (Init != nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); + delete this; + return nullptr; + } + } + else if (ValueType != TypeAuto) + { + if (Init) Init = new FxTypeCast(Init, ValueType, false); + SAFE_RESOLVE_OPT(Init, ctx); + } + else + { + if (Init == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Automatic type deduction requires an initializer for variable %s", Name.GetChars()); + delete this; + return nullptr; + } + SAFE_RESOLVE_OPT(Init, ctx); + if (Init->ValueType->RegType == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); + delete this; + return nullptr; + } + ValueType = Init->ValueType; + // check for undersized ints and floats. These are not allowed as local variables. + if (IsInteger() && ValueType->Align < sizeof(int)) ValueType = TypeSInt32; + else if (IsFloat() && ValueType->Align < sizeof(double)) ValueType = TypeFloat64; + } + if (Name != NAME_None) + { + for (auto l : ctx.Block->LocalVars) + { + if (l->Name == Name) + { + ScriptPosition.Message(MSG_ERROR, "Local variable %s already defined", Name.GetChars()); + l->ScriptPosition.Message(MSG_ERROR, "Original definition is here "); + delete this; + return nullptr; + } + } + } + ctx.Block->LocalVars.Push(this); + return this; +} + +ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) +{ + assert(!(VarFlags & VARF_Out)); // 'out' variables should never be initialized, they can only exist as function parameters. + + auto arrOffsetReg = build->Registers[REGT_INT].Get(1); + for (auto v : values) + { + ExpEmit emitval = v->Emit(build); + + int regtype = emitval.RegType; + if (regtype < REGT_INT || regtype > REGT_TYPE) + { + ScriptPosition.Message(MSG_ERROR, "Attempted to assign a non-value"); + return ExpEmit(); + } + if (emitval.Konst) + { + auto constval = static_cast(v); + int regNum = build->Registers[regtype].Get(1); + switch (regtype) + { + default: + case REGT_INT: + build->Emit(OP_LK, regNum, build->GetConstantInt(constval->GetValue().GetInt())); + build->Emit(OP_SW_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + break; + + case REGT_FLOAT: + build->Emit(OP_LKF, regNum, build->GetConstantInt(constval->GetValue().GetInt())); + build->Emit(OP_SDP_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + break; + + case REGT_POINTER: + build->Emit(OP_LKP, regNum, build->GetConstantInt(constval->GetValue().GetInt())); + build->Emit(OP_SP_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + break; + case REGT_STRING: + build->Emit(OP_LKS, regNum, build->GetConstantInt(constval->GetValue().GetInt())); + build->Emit(OP_SS_R, build->FramePointer.RegNum, regNum, arrOffsetReg); + break; + } + build->Emit(OP_ADD_RK, arrOffsetReg, arrOffsetReg, build->GetConstantInt(v->ValueType->Size)); + build->Registers[regtype].Return(regNum, 1); + + emitval.Free(build); + } + else + { + switch (regtype) + { + default: + case REGT_INT: + build->Emit(OP_SW_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); + break; + + case REGT_FLOAT: + build->Emit(OP_SDP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); + break; + + case REGT_POINTER: + build->Emit(OP_SP_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); + break; + case REGT_STRING: + build->Emit(OP_SS_R, build->FramePointer.RegNum, emitval.RegNum, arrOffsetReg); + break; + } + build->Emit(OP_ADD_RK, arrOffsetReg, arrOffsetReg, build->GetConstantInt(v->ValueType->Size)); + emitval.Free(build); + } + } + build->Registers[REGT_INT].Return(arrOffsetReg, 1); + + return ExpEmit(); +} diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 4140b9d9bf..79cf10bce6 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -301,6 +301,7 @@ enum EFxType EFX_ColorLiteral, EFX_GetDefaultByType, EFX_FontCast, + EFX_LocalArrayDeclaration, EFX_COUNT }; @@ -1806,6 +1807,7 @@ class FxCompoundStatement : public FxSequence friend class FxLocalVariableDeclaration; friend class FxStaticArray; friend class FxMultiAssign; + friend class FxLocalArrayDeclaration; public: FxCompoundStatement(const FScriptPosition &pos) : FxSequence(pos) {} @@ -2123,6 +2125,7 @@ class FxLocalVariableDeclaration : public FxExpression friend class FxCompoundStatement; friend class FxLocalVariable; friend class FxStaticArrayVariable; + friend class FxLocalArrayDeclaration; FName Name; FxExpression *Init; @@ -2181,4 +2184,22 @@ public: } }; +//========================================================================== +// +// +// +//========================================================================== + +class FxLocalArrayDeclaration : public FxLocalVariableDeclaration +{ + PType *ElementType; + FArgumentList values; + +public: + + FxLocalArrayDeclaration(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + #endif diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e6723c077a..06b16ed204 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -3557,17 +3557,18 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) type = ztype; } - FxExpression *val; if (node->InitIsArray) { - Error(node, "Compound initializer not implemented yet"); - val = nullptr; + FArgumentList args; + ConvertNodeList(args, node->Init); + // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. + list->Add(new FxLocalArrayDeclaration(ztype, node->Name, args, *ast)); } else { - val = node->Init ? ConvertNode(node->Init) : nullptr; + FxExpression *val = node->Init ? ConvertNode(node->Init) : nullptr; + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. } - list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. node = static_cast(node->SiblingNext); } while (node != loc->Vars);