From b3aa7c61a9f6dac4a0d4a5e4e780591e13890d8a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 23 Jan 2017 19:09:36 +0100 Subject: [PATCH] - fixed: Class and struct name lookup was not context aware. If a later module reused an existing name for a different class or struct type, this new name would completely shadow the old one, even in the base files. Changed it so that each compilation unit (i.e. each ZScript and DECORATE lump) get their own symbol table and can only see the symbol tables that got defined in lower numbered resource files so that later definitions do not pollute the available list of symbols when running the compiler backend and code generator - which happens after everything has been parsed. Another effect of this is that a mod that reuses the name of an internal global constant will only see its own constant, again reducing the risk of potential errors in case the internal definitions add some new values. Global constants are still discouraged from being used because what this does not and can not handle is the case that a mod defines a global constant with the same name as a class variable. In such a case the class variable will always take precedence for code inside that class. Note that the internal struct String had to be renamed for this because the stricter checks did not let the type String pass on the left side of a '.' anymore. - made PEnum inherit from PInt and not from PNamedType. The old inheritance broke nearly every check for integer compatibility in the compiler, so this hopefully leads to a working enum implementation. --- src/dobjgc.cpp | 2 +- src/dobjtype.cpp | 129 ++++++++++++++------ src/dobjtype.h | 62 +++++----- src/scripting/codegeneration/codegen.cpp | 52 ++++++--- src/scripting/codegeneration/codegen.h | 5 +- src/scripting/decorate/olddecorations.cpp | 3 +- src/scripting/decorate/thingdef_exp.cpp | 6 +- src/scripting/decorate/thingdef_parse.cpp | 53 ++++----- src/scripting/decorate/thingdef_states.cpp | 4 +- src/scripting/thingdef.cpp | 4 +- src/scripting/thingdef.h | 9 +- src/scripting/thingdef_data.cpp | 32 ++--- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/vm/vmbuilder.cpp | 6 +- src/scripting/vm/vmbuilder.h | 3 +- src/scripting/zscript/zcc_compile.cpp | 130 +++++++++------------ src/scripting/zscript/zcc_compile.h | 5 +- src/scripting/zscript/zcc_parser.cpp | 7 +- wadsrc/static/zscript/base.txt | 2 +- 19 files changed, 295 insertions(+), 221 deletions(-) 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::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(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(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(TypeTable.FindType(RUNTIME_CLASS(PClass), - /*FIXME:Outer*/0, zaname, NULL)); + return static_cast(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 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 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(TypeTable.FindType(RUNTIME_CLASS(PStruct), 0, (intptr_t)name, nullptr)); - if (ccls == nullptr) ccls = dyn_cast(TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), 0, (intptr_t)name, nullptr)); + auto type = static_cast(sym); + return dyn_cast(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(sym); + return dyn_cast(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(Object)->Identifier); + ccls = FindStructType(static_cast(Object)->Identifier, ctx); if (ccls != nullptr) static_cast(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(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(Self)->Identifier); + if (id == NAME_String) ccls = TypeStringStruct; + else ccls = FindStructType(id, ctx); if (ccls != nullptr) static_cast(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(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 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 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, TArrayScriptPosition); 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 &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); @@ -160,7 +161,7 @@ FName CheckCastKludges(FName in); void SetImplicitArgs(TArray *args, TArray *argflags, TArray *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 &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 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..1925a2eb6 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(node)->Flags & VARF_Native) + { + Error(node, "Cannot define native structs inside classes"); + static_cast(node)->Flags &= ~VARF_Native; + } ProcessStruct(static_cast(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(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 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(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 &Fiel { auto field = Fields[0]; FieldDesc *fd = nullptr; + FString str = FName(field->Names[0].Name); 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(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(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 88c931874..a14443b7d 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -86,7 +86,7 @@ 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(); @@ -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, ...);