mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 08:31:45 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
9a5cbbe6d8
18 changed files with 1077 additions and 315 deletions
|
@ -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}" )
|
||||||
|
|
|
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -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 -------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 ®);
|
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®);
|
||||||
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
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue