diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 7340e31f6..ae752b062 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6292,9 +6292,19 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) } else { - ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); - delete this; - return nullptr; + auto f = dyn_cast(sym); + if (f != nullptr && (f->Flags & VARF_Static | VARF_ReadOnly) == (VARF_Static | VARF_ReadOnly)) + { + auto x = new FxGlobalVariable(f, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return nullptr; + } } } } @@ -6933,6 +6943,15 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) BarrierSide = pmember->BarrierSide; } + // Even though this is global, static and readonly, we still need to do the scope checks for consistency. + if ((membervar->Flags & (VARF_Static | VARF_ReadOnly)) == (VARF_Static | VARF_ReadOnly)) + { + // This is a static constant array, which is stored at a constant address, like a global variable. + auto x = new FxGlobalVariable(membervar, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PPointer *ptrtype = dyn_cast(classx->ValueType); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6783ba86b..718ee1c51 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -198,7 +198,10 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) break; case AST_StaticArrayStatement: - cls->Arrays.Push(static_cast(node)); + if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) + { + cls->Arrays.Push(static_cast(node)); + } break; default: @@ -265,7 +268,10 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC break; case AST_StaticArrayStatement: - cls->Arrays.Push(static_cast(node)); + if (AddTreeNode(static_cast(node)->Id, node, &cls->TreeNodes)) + { + cls->Arrays.Push(static_cast(node)); + } break; default: @@ -826,6 +832,16 @@ void ZCCCompiler::CompileAllConstants() { Error(constantwork[i].node, "%s is not a constant", FName(constantwork[i].node->NodeName).GetChars()); } + + + for (auto s : Structs) + { + CompileArrays(s); + } + for (auto c : Classes) + { + CompileArrays(c); + } } //========================================================================== @@ -942,6 +958,69 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) } +void ZCCCompiler::CompileArrays(ZCC_StructWork *work) +{ + for(auto sas : work->Arrays) + { + PType *ztype = DetermineType(work->Type(), sas, sas->Id, sas->Type, false, true); + PType *ctype = ztype; + FArgumentList values; + + // Don't use narrow typea for casting. + if (ctype->IsA(RUNTIME_CLASS(PInt))) ctype = static_cast(ztype)->Unsigned ? TypeUInt32 : TypeSInt32; + else if (ctype == TypeFloat32) ctype = TypeFloat64; + + ConvertNodeList(values, sas->Values); + + bool fail = false; + FCompileContext ctx(OutNamespace, work->Type(), false); + + char *destmem = (char *)ClassDataAllocator.Alloc(values.Size() * ztype->Align); + memset(destmem, 0, values.Size() * ztype->Align); + char *copyp = destmem; + for (unsigned i = 0; i < values.Size(); i++) + { + values[i] = new FxTypeCast(values[i], ctype, false); + values[i] = values[i]->Resolve(ctx); + if (values[i] == nullptr) fail = true; + else if (!values[i]->isConstant()) + { + Error(sas, "Initializer must be constant"); + fail = true; + } + else + { + ExpVal val = static_cast(values[i])->GetValue(); + switch (ztype->GetRegType()) + { + default: + // should never happen + Error(sas, "Non-integral type in constant array"); + return; + + case REGT_INT: + ztype->SetValue(copyp, val.GetInt()); + break; + + case REGT_FLOAT: + ztype->SetValue(copyp, val.GetFloat()); + break; + + case REGT_POINTER: + *(void**)copyp = val.GetPointer(); + break; + + case REGT_STRING: + ::new(copyp) FString(val.GetString()); + break; + } + copyp += ztype->Align; + } + } + work->Type()->Symbols.AddSymbol(new PField(sas->Id, NewArray(ztype, values.Size()), VARF_Static | VARF_ReadOnly, (size_t)destmem)); + } +} + //========================================================================== // // ZCCCompiler :: NodeFromSymbol diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 5566eec64..9959f1420 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -102,6 +102,7 @@ private: void CompileAllConstants(); void AddConstant(ZCC_ConstantWork &constant); bool CompileConstant(ZCC_ConstantWork *def); + void CompileArrays(ZCC_StructWork *work); void CompileAllFields(); bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false);