diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 1a4f94935f..e7e511e985 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -11406,6 +11406,7 @@ FxLocalArrayDeclaration::FxLocalArrayDeclaration(PType *type, FName name, FArgum { ExprType = EFX_LocalArrayDeclaration; values = std::move(args); + clearExpr = nullptr; } FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) @@ -11421,6 +11422,16 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx) auto elementType = (static_cast (ValueType))->ElementType; auto elementCount = (static_cast (ValueType))->ElementCount; + // We HAVE to clear dynamic arrays before initializing them + if (IsDynamicArray()) + { + FArgumentList argsList; + argsList.Clear(); + + clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, (const FScriptPosition) ScriptPosition); + SAFE_RESOLVE(clearExpr, ctx); + } + if (values.Size() > elementCount) { ScriptPosition.Message(MSG_ERROR, "Initializer contains more elements than the array can contain"); @@ -11477,6 +11488,11 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) { assert(!(VarFlags & VARF_Out)); // 'out' variables should never be initialized, they can only exist as function parameters. + if (IsDynamicArray() && clearExpr != nullptr) + { + clearExpr->Emit(build); + } + auto elementSizeConst = build->GetConstantInt(static_cast(ValueType)->ElementSize); auto arrOffsetReg = build->Registers[REGT_INT].Get(1); build->Emit(OP_LK, arrOffsetReg, build->GetConstantInt(StackOffset)); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 88d79aebf3..39de03f93e 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -2194,6 +2194,7 @@ class FxLocalArrayDeclaration : public FxLocalVariableDeclaration { PType *ElementType; FArgumentList values; + FxExpression *clearExpr; public: diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 10cd4f525b..f62052de33 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1288,7 +1288,13 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArrayType->ArraySize != nullptr) { - fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type); + bool nosize; + fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type, &nosize); + + if (nosize) + { + Error(field, "Must specify array size"); + } } auto name = field->Names; @@ -1304,7 +1310,13 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArrayArraySize != nullptr) { - thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type); + bool nosize; + thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type, &nosize); + + if (nosize) + { + Error(field, "Must specify array size"); + } } if (varflags & VARF_Native) @@ -1805,7 +1817,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo // //========================================================================== -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls) +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize) { TArray indices; @@ -1817,6 +1829,11 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, node = static_cast(node->SiblingNext); } while (node != arraysize); + if (indices.Size() == 1 && indices [0]->Operation == PEX_Nil) + { + *nosize = true; + return baseType; + } FCompileContext ctx(OutNamespace, cls, false); for (auto node : indices) @@ -1839,6 +1856,8 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, } baseType = NewArray(baseType, size); } + + *nosize = false; return baseType; } @@ -3541,30 +3560,48 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (loc->Type->ArraySize != nullptr) { - ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass); + bool nosize; + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass, &nosize); + + if (nosize) + { + Error(node, "Must specify array size"); + } } do { PType *type; + bool nosize = false; if (node->ArraySize != nullptr) { - type = ResolveArraySize(ztype, node->ArraySize, ConvertClass); + type = ResolveArraySize(ztype, node->ArraySize, ConvertClass, &nosize); + + if (nosize && !node->InitIsArray) + { + Error(node, "Must specify array size for non-initialized arrays"); + } } else { type = ztype; } - if (node->InitIsArray) + if (node->InitIsArray && (type->isArray() || type->isDynArray() || nosize)) { - if (static_cast(type)->ElementType->isArray ()) + auto arrtype = static_cast(type); + if (!nosize && (arrtype->ElementType->isArray() || arrtype->ElementType->isDynArray())) { Error(node, "Compound initializer not implemented yet for multi-dimensional arrays"); } FArgumentList args; ConvertNodeList(args, node->Init); + + if (nosize) + { + type = NewArray(type, args.Size()); + } list->Add(new FxLocalArrayDeclaration(type, node->Name, args, 0, *node)); } else diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 238b5431c7..3a107ecfd1 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -114,7 +114,7 @@ private: bool CompileFlagDefs(PClass *type, TArray &FlagDefs, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); - PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize); PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype); void InitDefaults();