- 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.
This commit is contained in:
Christoph Oelckers 2017-01-23 19:09:36 +01:00
parent db4c5e090d
commit b3aa7c61a9
19 changed files with 295 additions and 221 deletions

View file

@ -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);

View file

@ -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();
}

View file

@ -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);

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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++;

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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);
}
//==========================================================================

View file

@ -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());

View file

@ -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();
};

View file

@ -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);
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);
}
}

View file

@ -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;
};

View file

@ -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)

View file

@ -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, ...);