diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 230dbeac7..0a44599d0 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -379,7 +379,7 @@ static void MarkRoot() Mark(PClass::AllClasses[i]); } // Mark global symbols - GlobalSymbols.MarkSymbols(); + Namespaces.MarkSymbols(); // Mark bot stuff. Mark(bglobal.firstthing); Mark(bglobal.body1); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c3ab87e11..dbd3e6d6f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -65,8 +65,9 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FNamespaceManager Namespaces; + FTypeTable TypeTable; -PSymbolTable GlobalSymbols; TArray<PClass *> PClass::AllClasses; bool PClass::bShutdown; bool PClass::bVMOperational; @@ -117,7 +118,7 @@ void DumpTypeTable() Printf("%4zu:", i); for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) { - Printf(" -> %s", ty->IsKindOf(RUNTIME_CLASS(PNamedType)) ? static_cast<PNamedType*>(ty)->TypeName.GetChars(): ty->GetClass()->TypeName.GetChars()); + Printf(" -> %s", ty->DescriptiveName()); len++; all++; } @@ -434,7 +435,7 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. - TypeStringStruct = NewNativeStruct(NAME_String, nullptr); + TypeStringStruct = NewNativeStruct("Stringstruct", nullptr); #ifdef __BIG_ENDIAN__ TypeColorStruct->AddField(NAME_a, TypeUInt8); TypeColorStruct->AddField(NAME_r, TypeUInt8); @@ -472,24 +473,24 @@ void PType::StaticInit() - GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2)); - GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3)); } @@ -1692,7 +1693,7 @@ PClassPointer *NewClassPointer(PClass *restrict) IMPLEMENT_CLASS(PEnum, false, true) IMPLEMENT_POINTERS_START(PEnum) - IMPLEMENT_POINTER(ValueType) + IMPLEMENT_POINTER(Outer) IMPLEMENT_POINTERS_END //========================================================================== @@ -1702,7 +1703,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PEnum::PEnum() -: ValueType(NULL) +: PInt(4, false) { mDescriptiveName = "Enum"; } @@ -1714,8 +1715,10 @@ PEnum::PEnum() //========================================================================== PEnum::PEnum(FName name, PTypeBase *outer) -: PNamedType(name, outer), ValueType(NULL) +: PInt(4, false) { + EnumName = name; + Outer = outer; mDescriptiveName.Format("Enum<%s>", name.GetChars()); } @@ -1731,6 +1734,7 @@ PEnum::PEnum(FName name, PTypeBase *outer) PEnum *NewEnum(FName name, PTypeBase *outer) { size_t bucket; + if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); if (etype == NULL) { @@ -2373,6 +2377,7 @@ size_t PStruct::PropagateMark() PStruct *NewStruct(FName name, PTypeBase *outer) { size_t bucket; + if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); if (stype == NULL) { @@ -2392,8 +2397,8 @@ IMPLEMENT_CLASS(PNativeStruct, false, false) // //========================================================================== -PNativeStruct::PNativeStruct(FName name) - : PStruct(name, nullptr) +PNativeStruct::PNativeStruct(FName name, PTypeBase *outer) + : PStruct(name, outer) { mDescriptiveName.Format("NativeStruct<%s>", name.GetChars()); Size = 0; @@ -2411,10 +2416,11 @@ PNativeStruct::PNativeStruct(FName name) PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) { size_t bucket; + if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); if (stype == NULL) { - stype = new PNativeStruct(name); + stype = new PNativeStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); } return static_cast<PNativeStruct *>(stype); @@ -2796,6 +2802,7 @@ void PClass::StaticInit () atterm (StaticShutdown); StaticBootstrap(); + Namespaces.GlobalNamespace = Namespaces.NewNamespace(0); FAutoSegIterator probe(CRegHead, CRegTail); @@ -2843,7 +2850,7 @@ void PClass::StaticShutdown () // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. TypeTable.Clear(); - GlobalSymbols.ReleaseSymbols(); + Namespaces.ReleaseSymbols(); for (i = 0; i < PClass::AllClasses.Size(); ++i) { @@ -3039,14 +3046,14 @@ void PClass::InsertIntoHash () size_t bucket; PType *found; - found = TypeTable.FindType(RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, &bucket); + found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); if (found != NULL) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } else { - TypeTable.AddType(this, RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, bucket); + TypeTable.AddType(this, RUNTIME_CLASS(PClass), 0, TypeName, bucket); } } @@ -3084,8 +3091,7 @@ PClass *PClass::FindClass (FName zaname) { return NULL; } - return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), - /*FIXME:Outer*/0, zaname, NULL)); + return static_cast<PClass *>(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL)); } //========================================================================== @@ -3376,7 +3382,7 @@ PClass *PClass::FindClassTentative(FName name) Derive(type, name); type->Size = TentativeClass; - TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); + TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); return type; } @@ -3835,3 +3841,60 @@ PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) Symbols.Insert(newsym->SymbolName, newsym); return NULL; } + +IMPLEMENT_CLASS(PNamespace, false, true) + +IMPLEMENT_POINTERS_START(PNamespace) +IMPLEMENT_POINTER(Parent) +IMPLEMENT_POINTERS_END + +PNamespace::PNamespace(int filenum, PNamespace *parent) +{ + Parent = parent; + if (parent) Symbols.SetParentTable(&parent->Symbols); + FileNum = filenum; +} + +size_t PNamespace::PropagateMark() +{ + GC::Mark(Parent); + return Symbols.MarkSymbols() + 1; +} + +FNamespaceManager::FNamespaceManager() +{ + GlobalNamespace = nullptr; +} + +PNamespace *FNamespaceManager::NewNamespace(int filenum) +{ + PNamespace *parent = nullptr; + // The parent will be the last namespace with this or a lower filenum. + // This ensures that DECORATE won't see the symbols of later files. + for (int i = AllNamespaces.Size() - 1; i >= 0; i--) + { + if (AllNamespaces[i]->FileNum <= filenum) + { + parent = AllNamespaces[i]; + break; + } + } + auto newns = new PNamespace(filenum, parent); + AllNamespaces.Push(newns); + return newns; +} + +size_t FNamespaceManager::MarkSymbols() +{ + for (auto ns : AllNamespaces) + { + GC::Mark(ns); + } + return AllNamespaces.Size(); +} + +void FNamespaceManager::ReleaseSymbols() +{ + GlobalNamespace = nullptr; + AllNamespaces.Clear(); +} diff --git a/src/dobjtype.h b/src/dobjtype.h index 7054095bd..61747134c 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -171,8 +171,6 @@ public: PSymbolTreeNode() : PSymbol(NAME_None) {} }; -extern PSymbolTable GlobalSymbols; - // Basic information shared by all types ------------------------------------ // Only one copy of a type is ever instantiated at one time. @@ -593,15 +591,15 @@ protected: // Compound types ----------------------------------------------------------- -class PEnum : public PNamedType +class PEnum : public PInt { - DECLARE_CLASS(PEnum, PNamedType); + DECLARE_CLASS(PEnum, PInt); HAS_OBJECT_POINTERS; public: PEnum(FName name, PTypeBase *outer); - PType *ValueType; - TMap<FName, int> Values; + PTypeBase *Outer; + FName EnumName; protected: PEnum(); }; @@ -710,7 +708,7 @@ class PNativeStruct : public PStruct { DECLARE_CLASS(PNativeStruct, PStruct); public: - PNativeStruct(FName name = NAME_None); + PNativeStruct(FName name = NAME_None, PTypeBase *outer = nullptr); }; class PPrototype : public PCompoundType @@ -986,31 +984,39 @@ public: PSymbolConstString() {} }; -// Enumerations for serializing types in an archive ------------------------- +// Namespaces -------------------------------------------------- -enum ETypeVal : BYTE +class PNamespace : public PTypeBase { - VAL_Int8, - VAL_UInt8, - VAL_Int16, - VAL_UInt16, - VAL_Int32, - VAL_UInt32, - VAL_Int64, - VAL_UInt64, - VAL_Zero, - VAL_One, - VAL_Float32, - VAL_Float64, - VAL_String, - VAL_Name, - VAL_Struct, - VAL_Array, - VAL_Object, - VAL_State, - VAL_Class, + DECLARE_CLASS(PNamespace, PTypeBase) + HAS_OBJECT_POINTERS; + +public: + PSymbolTable Symbols; + PNamespace *Parent; + int FileNum; // This is for blocking DECORATE access to later files. + + PNamespace() {} + PNamespace(int filenum, PNamespace *parent); + size_t PropagateMark(); }; +struct FNamespaceManager +{ + PNamespace *GlobalNamespace; + TArray<PNamespace *> AllNamespaces; + + FNamespaceManager(); + PNamespace *NewNamespace(int filenum); + size_t MarkSymbols(); + void ReleaseSymbols(); +}; + +extern FNamespaceManager Namespaces; + + +// Enumerations for serializing types in an archive ------------------------- + inline bool &DObject::BoolVar(FName field) { return *(bool*)ScriptVar(field, TypeBool); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6065050a9..1d16b182f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -95,14 +95,14 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump) - : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump) +FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump) + : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg) { if (fnc != nullptr) Class = fnc->OwningClass; } -FCompileContext::FCompileContext(PStruct *cls, bool fromdecorate) - : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1) +FCompileContext::FCompileContext(PNamespace *cg, PStruct *cls, bool fromdecorate) + : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg) { } @@ -119,7 +119,7 @@ PSymbol *FCompileContext::FindInSelfClass(FName identifier, PSymbolTable *&symt) } PSymbol *FCompileContext::FindGlobal(FName identifier) { - return GlobalSymbols.FindSymbol(identifier, true); + return CurGlobals->Symbols.FindSymbol(identifier, true); } void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) @@ -185,16 +185,30 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) } } -static PStruct *FindStructType(FName name) +static PStruct *FindStructType(FName name, FCompileContext &ctx) { - PStruct *ccls = PClass::FindClass(name); - if (ccls == nullptr) + auto sym = ctx.Class->Symbols.FindSymbol(name, true); + if (sym == nullptr) sym = ctx.CurGlobals->Symbols.FindSymbol(name, true); + if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { - ccls = dyn_cast<PStruct>(TypeTable.FindType(RUNTIME_CLASS(PStruct), 0, (intptr_t)name, nullptr)); - if (ccls == nullptr) ccls = dyn_cast<PStruct>(TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), 0, (intptr_t)name, nullptr)); + auto type = static_cast<PSymbolType*>(sym); + return dyn_cast<PStruct>(type->Type); } - return ccls; + return nullptr; } + +// This is for resolving class identifiers which need to be context aware, unlike class names. +static PClass *FindClassType(FName name, FCompileContext &ctx) +{ + auto sym = ctx.CurGlobals->Symbols.FindSymbol(name, true); + if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + auto type = static_cast<PSymbolType*>(sym); + return dyn_cast<PClass>(type->Type); + } + return nullptr; +} + //========================================================================== // // ExpEmit @@ -235,7 +249,7 @@ void ExpEmit::Reuse(VMFunctionBuilder *build) static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) { - PSymbol *sym = GlobalSymbols.FindSymbol(funcname, false); + PSymbol *sym = Namespaces.GlobalNamespace->Symbols.FindSymbol(funcname, false); if (sym == nullptr) { PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); @@ -243,7 +257,7 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall calldec->PrintableName = funcname.GetChars(); symfunc->Function = calldec; sym = symfunc; - GlobalSymbols.AddSymbol(sym); + Namespaces.GlobalNamespace->Symbols.AddSymbol(sym); } return sym; } @@ -5918,7 +5932,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - ccls = FindStructType(static_cast<FxIdentifier *>(Object)->Identifier); + ccls = FindStructType(static_cast<FxIdentifier *>(Object)->Identifier, ctx); if (ccls != nullptr) static_cast<FxIdentifier *>(Object)->noglobal = true; } @@ -7256,7 +7270,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) return x->Resolve(ctx); } - PClass *cls = PClass::FindClass(MethodName); + PClass *cls = FindClassType(MethodName, ctx); if (cls != nullptr && cls->bExported) { if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) @@ -7487,9 +7501,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ExprType == EFX_Identifier) { + auto id = static_cast<FxIdentifier *>(Self)->Identifier; // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - ccls = FindStructType(static_cast<FxIdentifier *>(Self)->Identifier); + if (id == NAME_String) ccls = TypeStringStruct; + else ccls = FindStructType(id, ctx); if (ccls != nullptr) static_cast<FxIdentifier *>(Self)->noglobal = true; } @@ -7500,8 +7516,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (ccls != nullptr) { // [ZZ] substitute ccls for String internal type. - if (ccls->TypeName == NAME_String) - ccls = TypeStringStruct; if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast<PClass *>(ccls)->bExported) { cls = ccls; @@ -9977,7 +9991,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (clsname != NAME_None) { - cls = PClass::FindClass(clsname); + cls = FindClassType(clsname, ctx); if (cls == nullptr) { /* lax */ diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 3dac463eb..7c18589c5 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -84,9 +84,10 @@ struct FCompileContext int Lump; bool Unsafe = false; TDeletingArray<FxLocalVariableDeclaration *> FunctionArgs; + PNamespace *CurGlobals; - FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); - FCompileContext(PStruct *cls, bool fromdecorate); // only to be used to resolve constants! + FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); + FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 077a75ad6..1eeed5796 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -100,7 +100,7 @@ static const char *RenderStyles[] = //========================================================================== PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName); -void ParseOldDecoration(FScanner &sc, EDefinitionType def) +void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) { Baggage bag; TArray<FState> StateArray; @@ -116,6 +116,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) typeName = FName(sc.String); type = DecoDerivedClass(FScriptPosition(sc), parent, typeName); ResetBaggage(&bag, parent); + bag.Namespace = ns; bag.Info = type; bag.fromDecorate = true; #ifdef _DEBUG diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index a0ab09510..2b0866dd8 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -82,13 +82,13 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls); -FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve) +FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, PNamespace *spc) { FxExpression *data = ParseExpressionM (sc, cls); - if (mustresolve) + if (spc) { - FCompileContext ctx(cls, true); + FCompileContext ctx(spc, cls, true); data = data->Resolve(ctx); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 837a03a32..81ab765f5 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -56,7 +56,7 @@ #include "v_text.h" #include "m_argv.h" -void ParseOldDecoration(FScanner &sc, EDefinitionType def); +void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns); EXTERN_CVAR(Bool, strictdecorate); @@ -101,12 +101,11 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN // // ParseParameter // -// Parses a parameter - either a default in a function declaration -// or an argument in a function call. +// Parses an argument in a function call. // //========================================================================== -FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant) +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type) { FxExpression *x = NULL; int v; @@ -118,12 +117,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c } else if (type == TypeBool || type == TypeSInt32 || type == TypeFloat64) { - x = ParseExpression (sc, cls, constant); - if (constant && !x->isConstant()) - { - sc.ScriptMessage("Default parameter must be constant."); - FScriptPosition::ErrorCounter++; - } + x = ParseExpression (sc, cls, nullptr); // Do automatic coercion between bools, ints and floats. if (type == TypeBool) { @@ -193,11 +187,10 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c x = new FxMultiNameState(sc.String, sc); } } - else if (!constant) + else { x = new FxRuntimeStateIndex(ParseExpression(sc, cls)); } - else sc.MustGetToken(TK_StringConst); // This is for the error. } else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) { // Actor name @@ -222,7 +215,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c // //========================================================================== -static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) +static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls, PNamespace *ns) { // Read the type and make sure it's int or float. if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Float)) @@ -231,7 +224,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) sc.MustGetToken(TK_Identifier); FName symname = sc.String; sc.MustGetToken('='); - FxExpression *expr = ParseExpression (sc, cls, true); + FxExpression *expr = ParseExpression (sc, cls, ns); sc.MustGetToken(';'); if (expr == nullptr) @@ -283,7 +276,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) // //========================================================================== -static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) +static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls, PNamespace *ns) { int currvalue = 0; @@ -294,7 +287,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FName symname = sc.String; if (sc.CheckToken('=')) { - FxExpression *expr = ParseExpression (sc, cls, true); + FxExpression *expr = ParseExpression (sc, cls, ns); if (expr != nullptr) { if (!expr->isConstant()) @@ -339,7 +332,7 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) // //========================================================================== -static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls) +static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls, PNamespace *ns) { PType *type; int maxelems = 1; @@ -381,7 +374,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { - FxExpression *expr = ParseExpression(sc, cls, true); + FxExpression *expr = ParseExpression(sc, cls, ns); if (expr == nullptr) { sc.ScriptMessage("Error while resolving array size"); @@ -1112,11 +1105,12 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) // Reads an actor definition // //========================================================================== -static void ParseActor(FScanner &sc) +static void ParseActor(FScanner &sc, PNamespace *ns) { PClassActor *info = NULL; Baggage bag; + bag.Namespace = ns; bag.fromDecorate = true; info = ParseActorHeader(sc, &bag); sc.MustGetToken('{'); @@ -1125,15 +1119,15 @@ static void ParseActor(FScanner &sc) switch (sc.TokenType) { case TK_Const: - ParseConstant (sc, &info->Symbols, info); + ParseConstant (sc, &info->Symbols, info, ns); break; case TK_Enum: - ParseEnum (sc, &info->Symbols, info); + ParseEnum (sc, &info->Symbols, info, ns); break; case TK_Var: - ParseUserVariable (sc, &info->Symbols, info); + ParseUserVariable (sc, &info->Symbols, info, ns); break; case TK_Identifier: @@ -1225,6 +1219,7 @@ static void ParseDamageDefinition(FScanner &sc) void ParseDecorate (FScanner &sc) { + auto ns = Namespaces.NewNamespace(sc.LumpNum); // Get actor class name. for(;;) { @@ -1255,11 +1250,11 @@ void ParseDecorate (FScanner &sc) } case TK_Const: - ParseConstant (sc, &GlobalSymbols, NULL); + ParseConstant (sc, &ns->Symbols, NULL, ns); break; case TK_Enum: - ParseEnum (sc, &GlobalSymbols, NULL); + ParseEnum (sc, &ns->Symbols, NULL, ns); break; case ';': @@ -1275,22 +1270,22 @@ void ParseDecorate (FScanner &sc) // so let's do a special case for this. if (sc.Compare("ACTOR")) { - ParseActor (sc); + ParseActor (sc, ns); break; } else if (sc.Compare("PICKUP")) { - ParseOldDecoration (sc, DEF_Pickup); + ParseOldDecoration (sc, DEF_Pickup, ns); break; } else if (sc.Compare("BREAKABLE")) { - ParseOldDecoration (sc, DEF_BreakableDecoration); + ParseOldDecoration (sc, DEF_BreakableDecoration, ns); break; } else if (sc.Compare("PROJECTILE")) { - ParseOldDecoration (sc, DEF_Projectile); + ParseOldDecoration (sc, DEF_Projectile, ns); break; } else if (sc.Compare("DAMAGETYPE")) @@ -1300,7 +1295,7 @@ void ParseDecorate (FScanner &sc) } default: sc.RestorePos(pos); - ParseOldDecoration(sc, DEF_Decoration); + ParseOldDecoration(sc, DEF_Decoration, ns); break; } } diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 671481de1..8e08fc038 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -343,7 +343,7 @@ endofstate: if (ScriptCode != nullptr) { auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags); - state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); + state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); } int count = bag.statedef.AddStates(&state, statestring, scp); if (count < 0) @@ -671,7 +671,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression else { // Use the generic parameter parser for everything else - x = ParseParameter(sc, cls, params[pnum], false); + x = ParseParameter(sc, cls, params[pnum]); } out_params.Push(x); pnum++; diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 9edb705bf..6776e70e8 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -216,7 +216,7 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam // //========================================================================== -void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum) +void CreateDamageFunction(PNamespace *OutNamespace, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum) { if (id == nullptr) { @@ -226,7 +226,7 @@ void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, { auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0); - defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); + defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); } } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 76a209722..37c247cbe 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -117,6 +117,7 @@ struct Baggage #ifdef _DEBUG FString ClassName; // This is here so that during debugging the class name can be seen #endif + PNamespace *Namespace; PClassActor *Info; bool DropItemSet; bool StateSet; @@ -132,7 +133,7 @@ struct Baggage inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) { - bag->DropItemList = NULL; + bag->DropItemList = nullptr; bag->DropItemSet = false; bag->CurrentState = 0; bag->fromDecorate = true; @@ -150,7 +151,7 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string); FieldDesc *FindField(PStruct *cls, const char * string); -FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); +FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, PNamespace *resolvenspc = nullptr); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); @@ -160,7 +161,7 @@ FName CheckCastKludges(FName in); void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FName> *argnames, PStruct *cls, DWORD funcflags, int useflags); PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); -void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); +void CreateDamageFunction(PNamespace *ns, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== // @@ -169,7 +170,7 @@ void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, //========================================================================== void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); -FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant); +FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type); enum diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 1dd8d6263..9fa33314e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -762,16 +762,16 @@ void InitThingdef() // expose the global validcount variable. PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); - GlobalSymbols.AddSymbol(vcf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(vcf); // expose the global Multiplayer variable. PField *multif = new PField("multiplayer", TypeBool, VARF_Native | VARF_ReadOnly | VARF_Static, (intptr_t)&multiplayer); - GlobalSymbols.AddSymbol(multif); + Namespaces.GlobalNamespace->Symbols.AddSymbol(multif); // set up a variable for the global level data structure PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); - GlobalSymbols.AddSymbol(levelf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(levelf); // Add the game data arrays to LevelLocals. lstruct->AddNativeField("sectors", NewPointer(NewResizableArray(sectorstruct), false), myoffsetof(FLevelLocals, sectors), VARF_Native); @@ -783,17 +783,17 @@ void InitThingdef() auto aact = NewPointer(NewResizableArray(NewClassPointer(RUNTIME_CLASS(AActor))), true); PField *aacf = new PField("AllActorClasses", aact, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PClassActor::AllActorClasses); - GlobalSymbols.AddSymbol(aacf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(aacf); // set up a variable for the DEH data PStruct *dstruct = NewNativeStruct("DehInfo", nullptr); PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh); - GlobalSymbols.AddSymbol(dehf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(dehf); // set up a variable for the global gameinfo data PStruct *gistruct = NewNativeStruct("GameInfoStruct", nullptr); PField *gi = new PField("gameinfo", gistruct, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gameinfo); - GlobalSymbols.AddSymbol(gi); + Namespaces.GlobalNamespace->Symbols.AddSymbol(gi); // set up a variable for the global players array. PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); @@ -801,33 +801,33 @@ void InitThingdef() pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); pstruct->AddNativeField("weapons", NewNativeStruct("WeaponSlots", nullptr), myoffsetof(player_t, weapons), VARF_Native); parray = NewArray(TypeBool, MAXPLAYERS); playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); playerf = new PField("gameaction", TypeUInt8, VARF_Native | VARF_Static, (intptr_t)&gameaction); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); playerf = new PField("skyflatnum", TypeTextureID, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&skyflatnum); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); playerf = new PField("globalfreeze", TypeUInt8, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&bglobal.freeze); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); playerf = new PField("consoleplayer", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&consoleplayer); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' // is to create a static variable from it and reference that in the script. Yuck!!! static AWeapon *wpnochg = WP_NOCHANGE; playerf = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); - GlobalSymbols.AddSymbol(playerf); + Namespaces.GlobalNamespace->Symbols.AddSymbol(playerf); // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. for (auto &fl : FlagLists) @@ -936,7 +936,7 @@ DEFINE_ACTION_FUNCTION(FStringTable, Localize) ACTION_RETURN_STRING(GStrings(&label[1])); } -DEFINE_ACTION_FUNCTION(FString, Replace) +DEFINE_ACTION_FUNCTION(FStringStruct, Replace) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_STRING(s1); @@ -1103,14 +1103,14 @@ static FString FStringFormat(VM_ARGS) return output; } -DEFINE_ACTION_FUNCTION(FString, Format) +DEFINE_ACTION_FUNCTION(FStringStruct, Format) { PARAM_PROLOGUE; FString s = FStringFormat(param, defaultparam, numparam, ret, numret); ACTION_RETURN_STRING(s); } -DEFINE_ACTION_FUNCTION(FString, AppendFormat) +DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) { PARAM_SELF_STRUCT_PROLOGUE(FString); // first parameter is the self pointer diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 807bd2a93..682300147 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -689,7 +689,7 @@ DEFINE_PROPERTY(damage, X, Actor) defaults->DamageVal = dmgval; // Only DECORATE can get here with a valid expression. - CreateDamageFunction(bag.Info, defaults, id, true, bag.Lumpnum); + CreateDamageFunction(bag.Namespace, bag.Info, defaults, id, true, bag.Lumpnum); } //========================================================================== diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 4886dba8c..46553ab72 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -802,7 +802,7 @@ void VMFunctionBuilder::BackpatchListToHere(TArray<size_t> &locs) //========================================================================== FFunctionBuildList FunctionBuildList; -VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum) +VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum) { auto func = code->GetDirectFunction(); if (func != nullptr) @@ -814,6 +814,8 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c //Printf("Adding %s\n", name.GetChars()); Item it; + assert(gnspc != nullptr); + it.CurGlobals = gnspc; it.Func = functype; it.Code = code; it.PrintableName = name; @@ -853,7 +855,7 @@ void FFunctionBuildList::Build() assert(item.Code != NULL); // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump); + FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump); // Allocate registers for the function's arguments and create local variable nodes before starting to resolve it. VMFunctionBuilder buildit(item.Func->GetImplicitArgs()); diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index b7746f1ce..300cfd843 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -141,6 +141,7 @@ class FFunctionBuildList FxExpression *Code = nullptr; PPrototype *Proto = nullptr; VMScriptFunction *Function = nullptr; + PNamespace *CurGlobals = nullptr; FString PrintableName; int StateIndex; int StateCount; @@ -151,7 +152,7 @@ class FFunctionBuildList TArray<Item> mItems; public: - VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum); + VMFunction *AddFunction(PNamespace *curglobals, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum); void Build(); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 714b56714..57bfbd0ec 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -74,7 +74,7 @@ static FString GetStringConst(FxExpression *ex, FCompileContext &ctx) int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) { - FCompileContext ctx(cls, false); + FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxIntCast(ConvertNode(node), false); ex = ex->Resolve(ctx); if (ex == nullptr) return 0; @@ -88,7 +88,7 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls) { - FCompileContext ctx(cls, false); + FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxStringCast(ConvertNode(node)); ex = ex->Resolve(ctx); if (ex == nullptr) return ""; @@ -154,7 +154,12 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) cls->Enums.Push(enumType); break; - case AST_Struct: + case AST_Struct: + if (static_cast<ZCC_Struct *>(node)->Flags & VARF_Native) + { + Error(node, "Cannot define native structs inside classes"); + static_cast<ZCC_Struct *>(node)->Flags &= ~VARF_Native; + } ProcessStruct(static_cast<ZCC_Struct *>(node), childnode, cls->cls); break; @@ -271,8 +276,8 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC // //========================================================================== -ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PSymbolTable &_outsymbols, int lumpnum) - : Outer(_outer), GlobalTreeNodes(&_symbols), OutputSymbols(&_outsymbols), AST(ast), Lump(lumpnum) +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum) + : Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum) { FScriptPosition::ResetErrorCounter(); // Group top-level nodes by type @@ -303,8 +308,8 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, { case AST_Enum: zenumType = static_cast<ZCC_Enum *>(node); - enumType = NewEnum(zenumType->NodeName, nullptr); - GlobalSymbols.AddSymbol(new PSymbolType(zenumType->NodeName, enumType)); + enumType = NewEnum(zenumType->NodeName, OutNamespace); + OutNamespace->Symbols.AddSymbol(new PSymbolType(zenumType->NodeName, enumType)); break; case AST_Class: @@ -468,13 +473,31 @@ void ZCCCompiler::CreateStructTypes() { for(auto s : Structs) { + PTypeBase *outer; + PSymbolTable *syms; + s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); - if (s->strct->Flags & ZCC_Native) - s->strct->Type = NewNativeStruct(s->NodeName(), nullptr); + if (s->Outer) + { + outer = s->Outer; + syms = &s->Outer->Symbols; + } else - s->strct->Type = NewStruct(s->NodeName(), s->Outer); + { + outer = OutNamespace; + syms = &OutNamespace->Symbols; + } + + if (s->strct->Flags & ZCC_Native) + { + s->strct->Type = NewNativeStruct(s->NodeName(), outer); + } + else + { + s->strct->Type = NewStruct(s->NodeName(), outer); + } s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type()); - GlobalSymbols.AddSymbol(s->strct->Symbol); + syms->AddSymbol(s->strct->Symbol); for (auto e : s->Enums) { @@ -577,7 +600,7 @@ void ZCCCompiler::CreateClassTypes() if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName()); c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); - GlobalSymbols.AddSymbol(c->cls->Symbol); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); OrigClasses.Delete(i--); donesomething = true; @@ -601,7 +624,7 @@ void ZCCCompiler::CreateClassTypes() // create a placeholder so that the compiler can continue looking for errors. c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); - GlobalSymbols.AddSymbol(c->cls->Symbol); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); OrigClasses.Delete(i--); donesomething = true; @@ -617,7 +640,7 @@ void ZCCCompiler::CreateClassTypes() Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); - GlobalSymbols.AddSymbol(c->cls->Symbol); + OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); } @@ -678,7 +701,7 @@ void ZCCCompiler::CompileAllConstants() // put all constants in one list to make resolving this easier. TArray<ZCC_ConstantWork> constantwork; - CopyConstants(constantwork, Constants, nullptr, OutputSymbols); + CopyConstants(constantwork, Constants, nullptr, &OutNamespace->Symbols); for (auto c : Classes) { CopyConstants(constantwork, c->Constants, c->Type(), &c->Type()->Symbols); @@ -810,7 +833,7 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) { - FCompileContext ctx(work->cls, false); + FCompileContext ctx(OutNamespace, work->cls, false); FxExpression *exp = ConvertNode(work->node->Value); try { @@ -836,49 +859,6 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) } -//========================================================================== -// -// ZCCCompiler :: IdentifyIdentifier -// -// Returns a node that represents what the identifer stands for. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *symt) -{ - // Check the symbol table for the identifier. - PSymbolTable *table; - PSymbol *sym = symt->FindSymbolInTable(idnode->Identifier, table); - // GlobalSymbols cannot be the parent of a class's symbol table so we have to look for global symbols explicitly. - if (sym == nullptr && symt != &GlobalSymbols) sym = GlobalSymbols.FindSymbolInTable(idnode->Identifier, table); - if (sym != nullptr) - { - ZCC_Expression *node = NodeFromSymbol(sym, idnode, table); - if (node != NULL) - { - return node; - } - } - else if (SimplifyingConstant) // leave unknown identifiers alone when simplifying non-constants. It is impossible to know what they are here. - { - // Also handle line specials. - // To call this like a function this needs to be done differently, but for resolving constants this is ok. - int spec = P_FindLineSpecial(FName(idnode->Identifier).GetChars()); - if (spec != 0) - { - ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); - val->Operation = PEX_ConstValue; - val->Type = TypeSInt32; - val->IntVal = spec; - return val; - } - - Error(idnode, "Unknown identifier '%s'", FName(idnode->Identifier).GetChars()); - idnode->ToErrorNode(); - } - return idnode; -} - //========================================================================== // // ZCCCompiler :: NodeFromSymbol @@ -1056,6 +1036,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel { auto field = Fields[0]; FieldDesc *fd = nullptr; + FString str = FName(field->Names[0].Name).GetChars(); PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); @@ -1394,10 +1375,15 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n } else { + // This doesn't check the class list directly but the current symbol table to ensure that + // this does not reference a type that got shadowed by a more local definition. + // We first look in the current class and its parents, and then in the current namespace and its parents. auto sym = outertype->Symbols.FindSymbol(ctype->Restriction->Id, true); - if (sym == nullptr) sym = GlobalSymbols.FindSymbol(ctype->Restriction->Id, false); + if (sym == nullptr) sym = OutNamespace->Symbols.FindSymbol(ctype->Restriction->Id, true); if (sym == nullptr) { + // A symbol with a given name cannot be reached from this definition point, so + // even if a class with the given name exists, it is not accessible. Error(field, "%s: Unknown identifier", FName(ctype->Restriction->Id).GetChars()); return TypeError; } @@ -1434,10 +1420,9 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) { // Check the symbol table for the identifier. - PSymbolTable *table; - PSymbol *sym = symt->FindSymbolInTable(type->UserType->Id, table); - // GlobalSymbols cannot be the parent of a class's symbol table so we have to look for global symbols explicitly. - if (sym == nullptr && symt != &GlobalSymbols) sym = GlobalSymbols.FindSymbolInTable(type->UserType->Id, table); + PSymbol *sym = symt->FindSymbol(type->UserType->Id, true); + // We first look in the current class and its parents, and then in the current namespace and its parents. + if (sym == nullptr) sym = OutNamespace->Symbols.FindSymbol(type->UserType->Id, true); if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto ptype = static_cast<PSymbolType *>(sym)->Type; @@ -1477,7 +1462,7 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, } while (node != arraysize); - FCompileContext ctx(cls, false); + FCompileContext ctx(OutNamespace, cls, false); for (auto node : indices) { // There is no float->int casting here. @@ -1526,7 +1511,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper const char * p = prop->params; auto exp = property->Values; - FCompileContext ctx(bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info, false); while (true) { FPropParam conv; @@ -1693,7 +1678,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop } auto exp = property->Values; - FCompileContext ctx(bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info, false); for (auto f : prop->Variables) { void *addr; @@ -1775,7 +1760,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro if (namenode->Id == NAME_DamageFunction) { auto x = ConvertNode(prop->Values); - CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false, Lump); + CreateDamageFunction(OutNamespace, cls, (AActor *)bag.Info->Defaults, x, false, Lump); ((AActor *)bag.Info->Defaults)->DamageVal = -1; return; } @@ -1923,6 +1908,7 @@ void ZCCCompiler::InitDefaults() #ifdef _DEBUG bag.ClassName = c->Type()->TypeName; #endif + bag.Namespace = OutNamespace; bag.Info = ti; bag.DropItemSet = false; bag.StateSet = false; @@ -2150,7 +2136,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool // It will also lose important type info about enums, once these get implemented // The code generator can do this properly for us. FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); - FCompileContext ctx(c->Type(), false); + FCompileContext ctx(OutNamespace, c->Type(), false); x = x->Resolve(ctx); if (x != nullptr) @@ -2258,7 +2244,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool auto code = ConvertAST(c->Type(), f->Body); if (code != nullptr) { - FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + FunctionBuildList.AddFunction(OutNamespace, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); } } } @@ -2527,7 +2513,7 @@ void ZCCCompiler::CompileStates() { state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); } - FCompileContext ctx(c->Type(), false); + FCompileContext ctx(OutNamespace, c->Type(), false); if (CheckRandom(sl->Duration)) { auto func = static_cast<ZCC_ExprFuncCall *>(sl->Duration); @@ -2581,7 +2567,7 @@ void ZCCCompiler::CompileStates() if (code != nullptr) { auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); - state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); + state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); } } diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 79dc3b135..a14443b7d 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -86,13 +86,13 @@ struct ZCC_ConstantWork class ZCCCompiler { public: - ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PSymbolTable &outsymbols, int lumpnum); + ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum); ~ZCCCompiler(); int Compile(); private: int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); - FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls); + FString StringConstFromNode(ZCC_TreeNode *node, PStruct *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); @@ -130,7 +130,6 @@ private: PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); - ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym); ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); @@ -147,7 +146,7 @@ private: DObject *Outer; PStruct *ConvertClass; // class type to be used when resoving symbols while converting an AST PSymbolTable *GlobalTreeNodes; - PSymbolTable *OutputSymbols; + PNamespace *OutNamespace; ZCC_AST &AST; int Lump; }; diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 872ab2cc8..501a7b2ea 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -226,6 +226,8 @@ static void InitTokenMap() #undef TOKENDEF #undef TOKENDEF2 +//**-------------------------------------------------------------------------- + static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCParseState &state) { int tokentype; @@ -311,6 +313,8 @@ parse_end: state.sc = nullptr; } +//**-------------------------------------------------------------------------- + static void DoParse(int lumpnum) { FScanner sc; @@ -395,7 +399,8 @@ static void DoParse(int lumpnum) } PSymbolTable symtable; - ZCCCompiler cc(state, NULL, symtable, GlobalSymbols, lumpnum); + auto newns = Wads.GetLumpFile(lumpnum) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(lumpnum)); + ZCCCompiler cc(state, NULL, symtable, newns, lumpnum); cc.Compile(); if (FScriptPosition::ErrorCounter > 0) diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index eab046372..a1177289e 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -305,7 +305,7 @@ enum EPickStart } // Although String is a builtin type, this is a convenient way to attach methods to it. -struct String native +struct StringStruct native { native void Replace(String pattern, String replacement); native static vararg String Format(String fmt, ...); diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index 3dba4ac2d..2aaa01ba8 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -127,7 +127,7 @@ extend class PlayerPawn { let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup")); armoritem.SaveAmount = 100*deh.BlueAC; - armoritem.SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5; + armoritem.SavePercent = gameinfo.Armor2Percent > 0 ? gameinfo.Armor2Percent * 100 : 50; if (!armoritem.CallTryPickup (self)) { armoritem.Destroy ();