diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 9f9b3c05c..65ffe2379 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -11409,86 +11409,75 @@ 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) +FxLocalArrayDeclaration::FxLocalArrayDeclaration(PType *type, FName name, FArgumentList &args, int varflags, const FScriptPosition &pos) + : FxLocalVariableDeclaration(type, name, nullptr, varflags, pos) { - ElementType = type; ExprType = EFX_LocalArrayDeclaration; values = std::move(args); } FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) { - CHECKRESOLVED(); + if (isresolved) + { + return this; + } + + FxLocalVariableDeclaration::Resolve(ctx); + + auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition); + auto elementType = (static_cast (ValueType))->ElementType; + auto elementCount = (static_cast (ValueType))->ElementCount; + + if (values.Size() > elementCount) + { + ScriptPosition.Message(MSG_ERROR, "Initializer contains more elements than the array can contain"); + delete this; + return nullptr; + } for (unsigned int i = 0; i < values.Size(); i++) { - auto v = values[i]->Resolve(ctx); + if (values[i] == nullptr) + { + delete this; + return nullptr; + } + + FxExpression *v = new FxTypeCast(values[i], elementType, false); + SAFE_RESOLVE(v, ctx); if (v == nullptr) { delete this; return nullptr; } + + if (!IsDynamicArray()) + { + if (v->IsNativeStruct() && elementType->isRealPointer() && elementType->toPointer()->PointedType == v->ValueType) + { + // Allow conversion of native structs to pointers of the same type. + // For all other types this is not needed. Structs are not assignable and classes can only exist as references. + bool writable; + v->RequestAddress(ctx, &writable); + v->ValueType = elementType; + } + } + else + { + FArgumentList argsList; + argsList.Clear(); + argsList.Push(v); + + FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition); + SAFE_RESOLVE(funcCall, ctx); + + v = funcCall; + } + 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; } @@ -11496,11 +11485,19 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) { assert(!(VarFlags & VARF_Out)); // 'out' variables should never be initialized, they can only exist as function parameters. + auto elementSizeConst = build->GetConstantInt(static_cast(ValueType)->ElementSize); auto arrOffsetReg = build->Registers[REGT_INT].Get(1); + build->Emit(OP_LK, arrOffsetReg, build->GetConstantInt(StackOffset)); + for (auto v : values) { ExpEmit emitval = v->Emit(build); + if (IsDynamicArray()) + { + continue; + } + int regtype = emitval.RegType; if (regtype < REGT_INT || regtype > REGT_TYPE) { @@ -11520,20 +11517,20 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) break; case REGT_FLOAT: - build->Emit(OP_LKF, regNum, build->GetConstantInt(constval->GetValue().GetInt())); + build->Emit(OP_LKF, regNum, build->GetConstantFloat(constval->GetValue().GetFloat())); 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_LKP, regNum, build->GetConstantAddress(constval->GetValue().GetPointer())); 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_LKS, regNum, build->GetConstantString(constval->GetValue().GetString())); 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); @@ -11554,13 +11551,15 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) 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->Emit(OP_ADD_RK, arrOffsetReg, arrOffsetReg, elementSizeConst); } build->Registers[REGT_INT].Return(arrOffsetReg, 1); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 79cf10bce..88d79aebf 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -2197,7 +2197,7 @@ class FxLocalArrayDeclaration : public FxLocalVariableDeclaration public: - FxLocalArrayDeclaration(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos); + FxLocalArrayDeclaration(PType *type, FName name, FArgumentList &args, int varflags, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 44e1dd6eb..9ca394f82 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -3568,10 +3568,13 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (node->InitIsArray) { + if (static_cast(type)->ElementType->isArray ()) + { + Error(node, "Compound initializer not implemented yet for multi-dimensional arrays"); + } 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)); + list->Add(new FxLocalArrayDeclaration(type, node->Name, args, 0, *node)); } else {