This commit is contained in:
Christoph Oelckers 2016-08-07 22:13:55 +02:00
commit 9a5cbbe6d8
18 changed files with 1077 additions and 315 deletions

View file

@ -509,8 +509,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" ) set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" )
set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" )
endif() endif()
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" )
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
endif()
endif() endif()
set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" ) set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" )
set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" )

View file

@ -147,6 +147,7 @@ static FCompatOption Options[] =
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 }, { "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
{ "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 },
{ "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 }, { "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 },
{ "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 },
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };

View file

@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 4: // Old ZDoom compat mode case 4: // Old ZDoom compat mode
v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; v = COMPATF_SOUNDTARGET | COMPATF_LIGHT;
w = COMPATF2_MULTIEXIT; w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT;
break; break;
case 5: // MBF compat mode case 5: // MBF compat mode
@ -630,6 +630,7 @@ CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF);
CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE);
CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT); CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT);
CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT);
//========================================================================== //==========================================================================
// //

View file

@ -18,6 +18,7 @@ typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
#define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Method (1<<1) // func has an implied self parameter
#define VARF_Action (1<<2) // func has implied owner and state parameters #define VARF_Action (1<<2) // func has implied owner and state parameters
#define VARF_Native (1<<3) // func is native code/don't auto serialize field #define VARF_Native (1<<3) // func is native code/don't auto serialize field
#define VARF_ReadOnly (1<<4) // field is read only, do not write to it
// Symbol information ------------------------------------------------------- // Symbol information -------------------------------------------------------

View file

@ -342,6 +342,7 @@ enum : unsigned int
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat() COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat()
COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script) COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script)
COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions
}; };
// Emulate old bugs for select maps. These are not exposed by a cvar // Emulate old bugs for select maps. These are not exposed by a cvar

View file

@ -1341,6 +1341,7 @@ MapFlagHandlers[] =
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF }, { "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
{ "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE },
{ "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT }, { "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT },
{ "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT },
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 },

View file

@ -891,16 +891,16 @@ static void DrawCoordinates(player_t * CPlayer)
default: default:
case 0: case 0:
vwidth = SCREENWIDTH; vwidth = SCREENWIDTH;
vheight = SCREENWIDTH; vheight = SCREENHEIGHT;
break; break;
case 1: case 1:
case 2: case 2:
vwidth = SCREENWIDTH/2; vwidth = SCREENWIDTH/2;
vheight = SCREENWIDTH/2; vheight = SCREENHEIGHT/2;
break; break;
case 3: case 3:
vwidth = SCREENWIDTH/4; vwidth = SCREENWIDTH/4;
vheight = SCREENWIDTH/4; vheight = SCREENHEIGHT/4;
break; break;
} }

View file

@ -654,6 +654,7 @@ xx(DecoCallLineSpecial)
xx(DecoNameToClass) xx(DecoNameToClass)
xx(DecoFindMultiNameState) xx(DecoFindMultiNameState)
xx(DecoFindSingleNameState) xx(DecoFindSingleNameState)
xx(DecoHandleRuntimeState)
xx(Damage) xx(Damage)
// basic type names // basic type names

View file

@ -434,7 +434,8 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
// If this teleport was caused by a move, P_TryMove() will handle the // If this teleport was caused by a move, P_TryMove() will handle the
// sector transition messages better than we can here. // sector transition messages better than we can here.
if (!(thing->flags6 & MF6_INTRYMOVE)) // This needs to be compatibility optioned because some older maps exploited this missing feature.
if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT))
{ {
thing->CheckSectorTransition(oldsec); thing->CheckSectorTransition(oldsec);
} }

View file

@ -270,23 +270,28 @@ static void FinishThingdef()
for (i = 0; i < StateTempCalls.Size(); ++i) for (i = 0; i < StateTempCalls.Size(); ++i)
{ {
FStateTempCall *tcall = StateTempCalls[i]; FStateTempCall *tcall = StateTempCalls[i];
VMFunction *func; VMFunction *func = nullptr;
assert(tcall->Code != NULL); assert(tcall->Code != NULL);
// Can we call this function directly without wrapping it in an // We don't know the return type in advance for anonymous functions.
// anonymous function? e.g. Are we passing any parameters to it? FCompileContext ctx(tcall->ActorClass, nullptr);
func = tcall->Code->GetDirectFunction(); tcall->Code = tcall->Code->Resolve(ctx);
if (func == NULL) tcall->Proto = ctx.ReturnProto;
{
FCompileContext ctx(tcall->ActorClass);
tcall->Code = tcall->Code->Resolve(ctx);
// Make sure resolving it didn't obliterate it. // Make sure resolving it didn't obliterate it.
if (tcall->Code != NULL) if (tcall->Code != nullptr)
{
// Can we call this function directly without wrapping it in an
// anonymous function? e.g. Are we passing any parameters to it?
func = tcall->Code->GetDirectFunction();
if (func == nullptr)
{ {
VMFunctionBuilder buildit; VMFunctionBuilder buildit;
assert(tcall->Proto != nullptr);
// Allocate registers used to pass parameters in. // Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers) // self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3); buildit.Registers[REGT_POINTER].Get(3);
@ -300,15 +305,7 @@ static void FinishThingdef()
// Generate prototype for this anonymous function // Generate prototype for this anonymous function
TArray<PType *> args(3); TArray<PType *> args(3);
SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action);
if (tcall->Proto != NULL) sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
{
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
}
else
{
TArray<PType *> norets(0);
sfunc->Proto = NewPrototype(norets, args);
}
func = sfunc; func = sfunc;
@ -321,11 +318,9 @@ static void FinishThingdef()
codesize += sfunc->CodeSize; codesize += sfunc->CodeSize;
} }
} }
}
if (tcall->Code != NULL)
{
delete tcall->Code; delete tcall->Code;
tcall->Code = NULL; tcall->Code = nullptr;
for (int k = 0; k < tcall->NumStates; ++k) for (int k = 0; k < tcall->NumStates; ++k)
{ {
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);

View file

@ -190,10 +190,9 @@ AFuncDesc *FindFunction(const char * string);
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params, void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
PFunction *afd, FString statestring, FStateDefinitions *statedef); PFunction *afd, FString statestring, FStateDefinitions *statedef);
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret); FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret);
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
FName CheckCastKludges(FName in); FName CheckCastKludges(FName in);
void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc);
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags); void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags);
PFunction *FindGlobalActionFunction(const char *name); PFunction *FindGlobalActionFunction(const char *name);
@ -356,6 +355,7 @@ int MatchString (const char *in, const char **strings);
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)
#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)

View file

@ -631,38 +631,38 @@ void InitThingdef()
// Define some member variables we feel like exposing to the user // Define some member variables we feel like exposing to the user
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
PType *array5 = NewArray(TypeSInt32, 5); PType *array5 = NewArray(TypeSInt32, 5);
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha))); symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw))); symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz))); symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz)));
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz))); symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz)));
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health)));
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass)));
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch))); symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch)));
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll))); symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll)));
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special)));
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only! symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only! symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only! symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X))); symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X))); symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height))); symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height)));
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius))); symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius)));
symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime)));
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange))); symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange)));
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed))); symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed)));
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold))); symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold))); symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
} }

View file

@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
// //
// ParseExpression // ParseExpression
// [GRB] Parses an expression and stores it into Expression array // [GRB] Parses an expression and stores it into Expression array
// It's worth mentioning that this is using C++ operator precedence
// //
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls);
@ -95,18 +96,83 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve)
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls)
{ {
FxExpression *condition = ParseExpressionL (sc, cls); FxExpression *base = ParseExpressionL (sc, cls);
if (sc.CheckToken('?')) if (sc.CheckToken('?'))
{ {
FxExpression *truex = ParseExpressionM (sc, cls); FxExpression *truex = ParseExpressionM (sc, cls);
sc.MustGetToken(':'); sc.MustGetToken(':');
FxExpression *falsex = ParseExpressionM (sc, cls); FxExpression *falsex = ParseExpressionM (sc, cls);
return new FxConditional(condition, truex, falsex); return new FxConditional(base, truex, falsex);
}
else if (sc.CheckToken('='))
{
FxExpression *right = ParseExpressionM(sc, cls);
return new FxAssign(base, right);
} }
else else
{ {
return condition; FxBinary *exp;
FxAssignSelf *left = new FxAssignSelf(sc);
sc.GetToken();
switch (sc.TokenType)
{
case TK_AddEq:
exp = new FxAddSub('+', left, nullptr);
break;
case TK_SubEq:
exp = new FxAddSub('-', left, nullptr);
break;
case TK_MulEq:
exp = new FxMulDiv('*', left, nullptr);
break;
case TK_DivEq:
exp = new FxMulDiv('/', left, nullptr);
break;
case TK_ModEq:
exp = new FxMulDiv('%', left, nullptr);
break;
case TK_LShiftEq:
exp = new FxBinaryInt(TK_LShift, left, nullptr);
break;
case TK_RShiftEq:
exp = new FxBinaryInt(TK_RShift, left, nullptr);
break;
case TK_URShiftEq:
exp = new FxBinaryInt(TK_URShift, left, nullptr);
break;
case TK_AndEq:
exp = new FxBinaryInt('&', left, nullptr);
break;
case TK_XorEq:
exp = new FxBinaryInt('^', left, nullptr);
break;
case TK_OrEq:
exp = new FxBinaryInt('|', left, nullptr);
break;
default:
sc.UnGet();
delete left;
return base;
}
exp->right = ParseExpressionM(sc, cls);
FxAssign *ret = new FxAssign(base, exp);
left->Assignment = ret;
return ret;
} }
} }
@ -257,6 +323,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls)
case '+': case '+':
return new FxPlusSign(ParseExpressionA (sc, cls)); return new FxPlusSign(ParseExpressionA (sc, cls));
case TK_Incr:
case TK_Decr:
return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType);
default: default:
sc.UnGet(); sc.UnGet();
return ParseExpressionA (sc, cls); return ParseExpressionA (sc, cls);
@ -312,6 +382,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls)
sc.MustGetToken(']'); sc.MustGetToken(']');
base_expr = new FxArrayElement(base_expr, index); base_expr = new FxArrayElement(base_expr, index);
} }
else if (sc.CheckToken(TK_Incr))
{
return new FxPostIncrDecr(base_expr, TK_Incr);
}
else if (sc.CheckToken(TK_Decr))
{
return new FxPostIncrDecr(base_expr, TK_Decr);
}
else break; else break;
} }
@ -357,6 +435,49 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
// a cheap way to get them working when people use "name" instead of 'name'. // a cheap way to get them working when people use "name" instead of 'name'.
return new FxConstant(FName(sc.String), scpos); return new FxConstant(FName(sc.String), scpos);
} }
else if (sc.CheckToken(TK_Bool))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxBoolCast(exp);
}
else if (sc.CheckToken(TK_Int))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxIntCast(exp);
}
else if (sc.CheckToken(TK_Float))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxFloatCast(exp);
}
else if (sc.CheckToken(TK_State))
{
sc.MustGetToken('(');
FxExpression *exp;
if (sc.CheckToken(TK_StringConst))
{
if (sc.String[0] == 0 || sc.Compare("None"))
{
exp = new FxConstant((FState*)nullptr, sc);
}
else
{
exp = new FxMultiNameState(sc.String, sc);
}
}
else
{
exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls));
}
sc.MustGetToken(')');
return exp;
}
else if (sc.CheckToken(TK_Identifier)) else if (sc.CheckToken(TK_Identifier))
{ {
FName identifier = FName(sc.String); FName identifier = FName(sc.String);
@ -374,6 +495,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
case NAME_Random2: case NAME_Random2:
return ParseRandom2(sc, cls); return ParseRandom2(sc, cls);
default: default:
if (cls != nullptr)
{
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult)
{
args = new FArgumentList;
if (sc.CheckToken('('))
{
sc.UnGet();
ParseFunctionParameters(sc, cls, *args, func, "", nullptr);
}
if (args->Size() == 0)
{
delete args;
args = nullptr;
}
return new FxVMFunctionCall(func, args, sc);
}
}
break; break;
} }
if (sc.CheckToken('(')) if (sc.CheckToken('('))
@ -392,17 +536,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
return ParseAtan2(sc, identifier, cls); return ParseAtan2(sc, identifier, cls);
default: default:
args = new FArgumentList; args = new FArgumentList;
func = (cls == nullptr) ? nullptr : dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
try try
{ {
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. if (!sc.CheckToken(')'))
if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult)
{
sc.UnGet();
ParseFunctionParameters(sc, cls, *args, func, "", NULL);
return new FxVMFunctionCall(func, args, sc);
}
else if (!sc.CheckToken(')'))
{ {
do do
{ {

View file

@ -62,14 +62,16 @@ class FxJumpStatement;
struct FCompileContext struct FCompileContext
{ {
TArray<FxJumpStatement *> Jumps; TArray<FxJumpStatement *> Jumps;
PPrototype *ReturnProto;
PClassActor *Class; PClassActor *Class;
FCompileContext(PClassActor *cls = nullptr); FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr);
PSymbol *FindInClass(FName identifier); PSymbol *FindInClass(FName identifier);
PSymbol *FindGlobal(FName identifier); PSymbol *FindGlobal(FName identifier);
void HandleJumps(int token, FxExpression *handler); void HandleJumps(int token, FxExpression *handler);
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
}; };
//========================================================================== //==========================================================================
@ -170,14 +172,14 @@ struct ExpVal
struct ExpEmit struct ExpEmit
{ {
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {} ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {} ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {} ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {}
ExpEmit(VMFunctionBuilder *build, int type); ExpEmit(VMFunctionBuilder *build, int type);
void Free(VMFunctionBuilder *build); void Free(VMFunctionBuilder *build);
void Reuse(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build);
BYTE RegNum, RegType, Konst:1, Fixed:1; BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1;
}; };
//========================================================================== //==========================================================================
@ -201,7 +203,8 @@ public:
virtual FxExpression *Resolve(FCompileContext &ctx); virtual FxExpression *Resolve(FCompileContext &ctx);
virtual bool isConstant() const; virtual bool isConstant() const;
virtual void RequestAddress(); virtual bool RequestAddress();
virtual PPrototype *ReturnProto();
virtual VMFunction *GetDirectFunction(); virtual VMFunction *GetDirectFunction();
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
@ -469,6 +472,84 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
//==========================================================================
//
// FxPreIncrDecr
//
//==========================================================================
class FxPreIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
bool AddressRequested;
bool AddressWritable;
public:
FxPreIncrDecr(FxExpression *base, int token);
~FxPreIncrDecr();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxPostIncrDecr
//
//==========================================================================
class FxPostIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
public:
FxPostIncrDecr(FxExpression *base, int token);
~FxPostIncrDecr();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxAssign
//
//==========================================================================
class FxAssign : public FxExpression
{
FxExpression *Base;
FxExpression *Right;
bool AddressRequested;
bool AddressWritable;
public:
FxAssign(FxExpression *base, FxExpression *right);
~FxAssign();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Address;
};
//==========================================================================
//
// FxAssignSelf
//
//==========================================================================
class FxAssignSelf : public FxExpression
{
public:
FxAssign *Assignment;
FxAssignSelf(const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//========================================================================== //==========================================================================
// //
// FxBinary // FxBinary
@ -670,6 +751,7 @@ public:
class FxRandom : public FxExpression class FxRandom : public FxExpression
{ {
protected: protected:
bool EmitTail;
FRandom *rng; FRandom *rng;
FxExpression *min, *max; FxExpression *min, *max;
@ -678,7 +760,7 @@ public:
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
~FxRandom(); ~FxRandom();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -724,6 +806,7 @@ public:
class FxRandom2 : public FxExpression class FxRandom2 : public FxExpression
{ {
bool EmitTail;
FRandom * rng; FRandom * rng;
FxExpression *mask; FxExpression *mask;
@ -732,7 +815,7 @@ public:
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos);
~FxRandom2(); ~FxRandom2();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -753,7 +836,7 @@ public:
FxClassMember(FxExpression*, PField*, const FScriptPosition&); FxClassMember(FxExpression*, PField*, const FScriptPosition&);
~FxClassMember(); ~FxClassMember();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
void RequestAddress(); bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -796,12 +879,13 @@ class FxArrayElement : public FxExpression
public: public:
FxExpression *Array; FxExpression *Array;
FxExpression *index; FxExpression *index;
//bool AddressRequested; bool AddressRequested;
bool AddressWritable;
FxArrayElement(FxExpression*, FxExpression*); FxArrayElement(FxExpression*, FxExpression*);
~FxArrayElement(); ~FxArrayElement();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
//void RequestAddress(); bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -836,8 +920,9 @@ public:
class FxActionSpecialCall : public FxExpression class FxActionSpecialCall : public FxExpression
{ {
FxExpression *Self;
int Special; int Special;
bool EmitTail;
FxExpression *Self;
FArgumentList *ArgList; FArgumentList *ArgList;
public: public:
@ -845,6 +930,7 @@ public:
FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos);
~FxActionSpecialCall(); ~FxActionSpecialCall();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -875,6 +961,7 @@ public:
class FxVMFunctionCall : public FxExpression class FxVMFunctionCall : public FxExpression
{ {
bool EmitTail;
PFunction *Function; PFunction *Function;
FArgumentList *ArgList; FArgumentList *ArgList;
@ -882,13 +969,10 @@ public:
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
~FxVMFunctionCall(); ~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
VMFunction *GetDirectFunction();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit &reg); bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit &reg);
unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); }
PFunction *GetFunction() const { return Function; }
VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; }
bool IsDirectFunction();
}; };
//========================================================================== //==========================================================================
@ -1010,10 +1094,10 @@ public:
class FxReturnStatement : public FxExpression class FxReturnStatement : public FxExpression
{ {
FxVMFunctionCall *Call; FxExpression *Value;
public: public:
FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos); FxReturnStatement(FxExpression *value, const FScriptPosition &pos);
~FxReturnStatement(); ~FxReturnStatement();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
@ -1058,6 +1142,26 @@ public:
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
}; };
//==========================================================================
//
// Same as above except for expressions which means it will have to be
// evaluated at runtime
//
//==========================================================================
class FxRuntimeStateIndex : public FxExpression
{
bool EmitTail;
FxExpression *Index;
public:
FxRuntimeStateIndex(FxExpression *index);
~FxRuntimeStateIndex();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build);
};
//========================================================================== //==========================================================================
// //
// //

File diff suppressed because it is too large Load diff

View file

@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
else if (type == TypeState) else if (type == TypeState)
{ {
// This forces quotation marks around the state name. // This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst); if (sc.CheckToken(TK_StringConst))
if (sc.String[0] == 0 || sc.Compare("None"))
{ {
x = new FxConstant((FState*)NULL, sc); if (sc.String[0] == 0 || sc.Compare("None"))
}
else if (sc.Compare("*"))
{
if (constant)
{ {
x = new FxConstant((FState*)(intptr_t)-1, sc); x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
{
x = new FxMultiNameState(sc.String, sc);
} }
else sc.ScriptError("Invalid state name '*'");
} }
else else if (!constant)
{ {
x = new FxMultiNameState(sc.String, sc); x = new FxRuntimeStateIndex(ParseExpression(sc, cls));
} }
else sc.MustGetToken(TK_StringConst); // This is for the error.
} }
else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
{ // Actor name { // Actor name

View file

@ -315,10 +315,10 @@ do_stop:
} }
bool hasfinalret; bool hasfinalret;
tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret); tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret);
if (!hasfinalret) if (!hasfinalret && tcall->Code != nullptr)
{ {
AddImplicitReturn(static_cast<FxSequence*>(tcall->Code), tcall->Proto, sc); static_cast<FxSequence *>(tcall->Code)->Add(new FxReturnStatement(nullptr, sc));
} }
goto endofstate; goto endofstate;
} }
@ -351,125 +351,37 @@ endofstate:
sc.SetEscape(true); // re-enable escape sequences sc.SetEscape(true); // re-enable escape sequences
} }
//==========================================================================
//
// AddImplicitReturn
//
// Adds an implied return; statement to the end of a code sequence.
//
//==========================================================================
void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc)
{
if (code == NULL)
{
return;
}
if (proto == NULL || proto->ReturnTypes.Size() == 0)
{ // Returns nothing. Good. We can safely add an implied return.
code->Add(new FxReturnStatement(NULL, sc));
}
else
{ // Something was returned earlier in the sequence. Make it an error
// instead of adding an implicit one.
sc.ScriptError("Not all paths return a value");
}
}
//==========================================================================
//
// ReturnCheck
//
// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1.
// If neither is null, checks if both prototypes define the same return
// types. If not, an error is flagged.
//
//==========================================================================
static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc)
{
if (proto1 == NULL)
{
return proto2;
}
if (proto2 == NULL)
{
return proto1;
}
// A prototype that defines fewer return types can be compatible with
// one that defines more if the shorter one matches the initial types
// for the longer one.
if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size())
{ // Make proto1 the shorter one to avoid code duplication below.
swapvalues(proto1, proto2);
}
// If one prototype returns nothing, they both must.
if (proto1->ReturnTypes.Size() == 0)
{
if (proto2->ReturnTypes.Size() == 0)
{
return proto1;
}
proto1 = NULL;
}
else
{
for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i)
{
if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i])
{ // Incompatible
proto1 = NULL;
break;
}
}
}
if (proto1 == NULL)
{
sc.ScriptError("Return types are incompatible");
}
return proto1;
}
//========================================================================== //==========================================================================
// //
// ParseActions // ParseActions
// //
// If this action block contains any return statements, the prototype for
// one of them will be returned. This is used for deducing the return type
// of anonymous functions. All called functions passed to return must have
// matching return types.
//
//========================================================================== //==========================================================================
static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
PPrototype *&retproto, bool &lastwasret)
{ {
FxExpression *add, *cond; FxExpression *add, *cond;
FxExpression *true_part, *false_part = NULL; FxExpression *true_part, *false_part = nullptr;
PPrototype *true_proto, *false_proto = NULL;
bool true_ret, false_ret = false; bool true_ret, false_ret = false;
sc.MustGetStringName("("); sc.MustGetStringName("(");
cond = ParseExpression(sc, bag.Info); cond = ParseExpression(sc, bag.Info);
sc.MustGetStringName(")"); sc.MustGetStringName(")");
sc.MustGetStringName("{"); // braces are mandatory sc.MustGetStringName("{"); // braces are mandatory
true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret); true_part = ParseActions(sc, state, statestring, bag, true_ret);
sc.MustGetString(); sc.MustGetString();
if (sc.Compare("else")) if (sc.Compare("else"))
{ {
if (sc.CheckString("if")) if (sc.CheckString("if"))
{ {
false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret); false_part = ParseIf(sc, state, statestring, bag, false_ret);
} }
else else
{ {
sc.MustGetStringName("{"); // braces are still mandatory sc.MustGetStringName("{"); // braces are still mandatory
false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret); false_part = ParseActions(sc, state, statestring, bag, false_ret);
sc.MustGetString(); sc.MustGetString();
} }
} }
add = new FxIfStatement(cond, true_part, false_part, sc); add = new FxIfStatement(cond, true_part, false_part, sc);
retproto = ReturnCheck(retproto, true_proto, sc);
retproto = ReturnCheck(retproto, false_proto, sc);
// If one side does not end with a return, we don't consider the if statement // If one side does not end with a return, we don't consider the if statement
// to end with a return. If the else case is missing, it can never be considered // to end with a return. If the else case is missing, it can never be considered
// as ending with a return. // as ending with a return.
@ -480,11 +392,9 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba
return add; return add;
} }
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
PPrototype *&retproto, bool &lastwasret)
{ {
FxExpression *cond, *code; FxExpression *cond, *code;
PPrototype *proto;
bool ret; bool ret;
sc.MustGetStringName("("); sc.MustGetStringName("(");
@ -492,24 +402,21 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring,
sc.MustGetStringName(")"); sc.MustGetStringName(")");
sc.MustGetStringName("{"); // Enforce braces like for if statements. sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret); code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetString(); sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false; // A while loop always jumps back. lastwasret = false; // A while loop always jumps back.
return new FxWhileLoop(cond, code, sc); return new FxWhileLoop(cond, code, sc);
} }
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
PPrototype *&retproto, bool &lastwasret)
{ {
FxExpression *cond, *code; FxExpression *cond, *code;
PPrototype *proto;
bool ret; bool ret;
sc.MustGetStringName("{"); // Enforce braces like for if statements. sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret); code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetStringName("while"); sc.MustGetStringName("while");
sc.MustGetStringName("("); sc.MustGetStringName("(");
@ -518,20 +425,17 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin
sc.MustGetStringName(";"); sc.MustGetStringName(";");
sc.MustGetString(); sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false; lastwasret = false;
return new FxDoWhileLoop(cond, code, sc); return new FxDoWhileLoop(cond, code, sc);
} }
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
PPrototype *&retproto, bool &lastwasret)
{ {
FxExpression *init = nullptr; FxExpression *init = nullptr;
FxExpression *cond = nullptr; FxExpression *cond = nullptr;
FxExpression *iter = nullptr; FxExpression *iter = nullptr;
FxExpression *code = nullptr; FxExpression *code = nullptr;
PPrototype *proto;
bool ret; bool ret;
// Parse the statements. // Parse the statements.
@ -539,7 +443,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
sc.MustGetString(); sc.MustGetString();
if (!sc.Compare(";")) if (!sc.Compare(";"))
{ {
init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now. sc.UnGet();
init = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";"); sc.MustGetStringName(";");
} }
sc.MustGetString(); sc.MustGetString();
@ -552,30 +457,28 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
sc.MustGetString(); sc.MustGetString();
if (!sc.Compare(")")) if (!sc.Compare(")"))
{ {
iter = ParseAction(sc, state, statestring, bag); sc.UnGet();
iter = ParseExpression(sc, bag.Info);
sc.MustGetStringName(")"); sc.MustGetStringName(")");
} }
// Now parse the loop's content. // Now parse the loop's content.
sc.MustGetStringName("{"); // Enforce braces like for if statements. sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret); code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetString(); sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false; lastwasret = false;
return new FxForLoop(init, cond, iter, code, sc); return new FxForLoop(init, cond, iter, code, sc);
} }
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret)
PPrototype *&retproto, bool &endswithret)
{ {
// If it's not a '{', then it should be a single action. // If it's not a '{', then it should be a single action.
// Otherwise, it's a sequence of actions. // Otherwise, it's a sequence of actions.
if (!sc.Compare("{")) if (!sc.Compare("{"))
{ {
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
retproto = call->GetVMFunction()->Proto;
endswithret = true; endswithret = true;
return new FxReturnStatement(call, sc); return new FxReturnStatement(call, sc);
} }
@ -583,7 +486,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
const FScriptPosition pos(sc); const FScriptPosition pos(sc);
FxSequence *seq = NULL; FxSequence *seq = NULL;
PPrototype *proto = NULL;
bool lastwasret = false; bool lastwasret = false;
sc.MustGetString(); sc.MustGetString();
@ -593,38 +495,31 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
lastwasret = false; lastwasret = false;
if (sc.Compare("if")) if (sc.Compare("if"))
{ // Handle an if statement { // Handle an if statement
add = ParseIf(sc, state, statestring, bag, proto, lastwasret); add = ParseIf(sc, state, statestring, bag, lastwasret);
} }
else if (sc.Compare("while")) else if (sc.Compare("while"))
{ // Handle a while loop { // Handle a while loop
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret); add = ParseWhile(sc, state, statestring, bag, lastwasret);
} }
else if (sc.Compare("do")) else if (sc.Compare("do"))
{ // Handle a do-while loop { // Handle a do-while loop
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret); add = ParseDoWhile(sc, state, statestring, bag, lastwasret);
} }
else if (sc.Compare("for")) else if (sc.Compare("for"))
{ // Handle a for loop { // Handle a for loop
add = ParseFor(sc, state, statestring, bag, proto, lastwasret); add = ParseFor(sc, state, statestring, bag, lastwasret);
} }
else if (sc.Compare("return")) else if (sc.Compare("return"))
{ // Handle a return statement { // Handle a return statement
lastwasret = true; lastwasret = true;
FxVMFunctionCall *retexp = NULL; FxExpression *retexp = nullptr;
PPrototype *retproto;
sc.MustGetString(); sc.MustGetString();
if (!sc.Compare(";")) if (!sc.Compare(";"))
{ {
retexp = ParseAction(sc, state, statestring, bag); sc.UnGet();
retexp = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";"); sc.MustGetStringName(";");
retproto = retexp->GetVMFunction()->Proto;
} }
else
{ // Returning nothing; we still need a prototype for that.
TArray<PType *> notypes(0);
retproto = NewPrototype(notypes, notypes);
}
proto = ReturnCheck(proto, retproto, sc);
sc.MustGetString(); sc.MustGetString();
add = new FxReturnStatement(retexp, sc); add = new FxReturnStatement(retexp, sc);
} }
@ -641,8 +536,9 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
sc.MustGetString(); sc.MustGetString();
} }
else else
{ // Handle a regular action function call { // Handle a regular expression
add = ParseAction(sc, state, statestring, bag); sc.UnGet();
add = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";"); sc.MustGetStringName(";");
sc.MustGetString(); sc.MustGetString();
} }
@ -657,7 +553,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
} }
} }
endswithret = lastwasret; endswithret = lastwasret;
retproto = proto;
return seq; return seq;
} }

View file

@ -430,6 +430,11 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07
maskedmidtex maskedmidtex
} }
7B82B12A6990E09553B12FDB4E3824A0 // hti.wad map01
{
teleport
}
D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update 19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
{ {