- 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
commit b3aa7c61a9
19 changed files with 294 additions and 220 deletions

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