Merge remote-tracking branch 'gzdoom/staging'
This commit is contained in:
commit
73ada7f84b
214 changed files with 23523 additions and 1206 deletions
|
|
@ -43,11 +43,13 @@
|
|||
#include "texturemanager.h"
|
||||
#include "m_random.h"
|
||||
#include "v_font.h"
|
||||
#include "palettecontainer.h"
|
||||
|
||||
|
||||
extern FRandom pr_exrandom;
|
||||
FMemArena FxAlloc(65536);
|
||||
CompileEnvironment compileEnvironment;
|
||||
FTranslationID R_FindCustomTranslation(FName name);
|
||||
|
||||
struct FLOP
|
||||
{
|
||||
|
|
@ -161,6 +163,12 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
|
|||
PType* expected = ReturnProto->ReturnTypes[i];
|
||||
PType* actual = proto->ReturnTypes[i];
|
||||
if (swapped) std::swap(expected, actual);
|
||||
// this must pass for older ZScripts.
|
||||
if (Version < MakeVersion(4, 12, 0))
|
||||
{
|
||||
if (expected == TypeTranslationID) expected = TypeSInt32;
|
||||
if (actual == TypeTranslationID) actual = TypeSInt32;
|
||||
}
|
||||
|
||||
if (expected != actual && !AreCompatiblePointerTypes(expected, actual))
|
||||
{ // Incompatible
|
||||
|
|
@ -916,6 +924,17 @@ FxExpression *FxBoolCast::Resolve(FCompileContext &ctx)
|
|||
ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit from = basex->Emit(build);
|
||||
|
||||
if(from.Konst && from.RegType == REGT_INT)
|
||||
{ // this is needed here because the int const assign optimization returns a constant
|
||||
ExpEmit to;
|
||||
to.Konst = true;
|
||||
to.RegType = REGT_INT;
|
||||
to.RegNum = build->GetConstantInt(!!build->FindConstantInt(from.RegNum));
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
assert(!from.Konst);
|
||||
assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER);
|
||||
|
||||
|
|
@ -982,6 +1001,19 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
|
|||
|
||||
if (basex->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
if (basex->ValueType == TypeTranslationID)
|
||||
{
|
||||
// translation IDs must be entirely incompatible with ints, not even allowing an explicit conversion,
|
||||
// but since the type was only introduced in version 4.12, older ZScript versions must allow this conversion.
|
||||
if (ctx.Version < MakeVersion(4, 12, 0))
|
||||
{
|
||||
FxExpression* x = basex;
|
||||
x->ValueType = ValueType;
|
||||
basex = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
if (basex->ValueType->isNumeric() || Explicit) // names can be converted to int, but only with an explicit type cast.
|
||||
{
|
||||
FxExpression *x = basex;
|
||||
|
|
@ -995,7 +1027,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
|
|||
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this serious error needs to be reduced to a warning. :(
|
||||
// At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE.
|
||||
if (!basex->isConstant())
|
||||
ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
|
||||
ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a %s", basex->ValueType->DescriptiveName());
|
||||
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
|
||||
FxExpression * x = new FxConstant(0, ScriptPosition);
|
||||
delete this;
|
||||
|
|
@ -1116,7 +1148,8 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :(
|
||||
// At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE.
|
||||
if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
|
||||
if (!basex->isConstant())
|
||||
ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a %s", basex->ValueType->DescriptiveName());
|
||||
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
|
||||
FxExpression *x = new FxConstant(0.0, ScriptPosition);
|
||||
delete this;
|
||||
|
|
@ -1140,7 +1173,15 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
|
|||
ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit from = basex->Emit(build);
|
||||
//assert(!from.Konst);
|
||||
if(from.Konst && from.RegType == REGT_INT)
|
||||
{ // this is needed here because the int const assign optimization returns a constant
|
||||
ExpEmit to;
|
||||
to.Konst = true;
|
||||
to.RegType = REGT_FLOAT;
|
||||
to.RegNum = build->GetConstantFloat(build->FindConstantInt(from.RegNum));
|
||||
return to;
|
||||
}
|
||||
|
||||
assert(basex->ValueType->GetRegType() == REGT_INT);
|
||||
from.Free(build);
|
||||
ExpEmit to(build, REGT_FLOAT);
|
||||
|
|
@ -1515,6 +1556,107 @@ ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build)
|
|||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTranslationCast::FxTranslationCast(FxExpression* x)
|
||||
: FxExpression(EFX_TranslationCast, x->ScriptPosition)
|
||||
{
|
||||
basex = x;
|
||||
ValueType = TypeTranslationID;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTranslationCast::~FxTranslationCast()
|
||||
{
|
||||
SAFE_DELETE(basex);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression* FxTranslationCast::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(basex, ctx);
|
||||
|
||||
if (basex->ValueType->isInt())
|
||||
{
|
||||
// 0 is a valid constant for translations, meaning 'no translation at all'. note that this conversion ONLY allows a constant!
|
||||
if (basex->isConstant() && static_cast<FxConstant*>(basex)->GetValue().GetInt() == 0)
|
||||
{
|
||||
FxExpression* x = basex;
|
||||
x->ValueType = TypeTranslationID;
|
||||
basex = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
if (ctx.Version < MakeVersion(4, 12, 0))
|
||||
{
|
||||
// only allow this conversion as a fallback
|
||||
FxExpression* x = basex;
|
||||
x->ValueType = TypeTranslationID;
|
||||
basex = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
else if (basex->ValueType == TypeString || basex->ValueType == TypeName)
|
||||
{
|
||||
if (basex->isConstant())
|
||||
{
|
||||
ExpVal constval = static_cast<FxConstant*>(basex)->GetValue();
|
||||
FxExpression* x = new FxConstant(R_FindCustomTranslation(constval.GetName()), ScriptPosition);
|
||||
x->ValueType = TypeTranslationID;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
else if (basex->ValueType == TypeString)
|
||||
{
|
||||
basex = new FxNameCast(basex, true);
|
||||
basex = basex->Resolve(ctx);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot convert to translation ID");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxTranslationCast::Emit(VMFunctionBuilder* build)
|
||||
{
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
|
||||
VMFunction* callfunc;
|
||||
auto sym = FindBuiltinFunction(NAME_BuiltinFindTranslation);
|
||||
|
||||
assert(sym);
|
||||
callfunc = sym->Variants[0].Implementation;
|
||||
|
||||
FunctionCallEmitter emitters(callfunc);
|
||||
emitters.AddParameter(build, basex);
|
||||
emitters.AddReturn(REGT_INT);
|
||||
return emitters.EmitCall(build);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
@ -1747,6 +1889,14 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
|||
delete this;
|
||||
return x;
|
||||
}
|
||||
else if (ValueType == TypeTranslationID)
|
||||
{
|
||||
FxExpression* x = new FxTranslationCast(basex);
|
||||
x = x->Resolve(ctx);
|
||||
basex = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
else if (ValueType == TypeColor)
|
||||
{
|
||||
FxExpression *x = new FxColorCast(basex);
|
||||
|
|
@ -1973,7 +2123,17 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
//assert(ValueType == Operand->ValueType);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
if(from.Konst && from.RegType == REGT_INT)
|
||||
{ // this is needed here because the int const assign optimization returns a constant
|
||||
ExpEmit to;
|
||||
to.Konst = true;
|
||||
to.RegType = REGT_INT;
|
||||
to.RegNum = build->GetConstantInt(-build->FindConstantInt(from.RegNum));
|
||||
return to;
|
||||
}
|
||||
|
||||
ExpEmit to;
|
||||
|
||||
assert(from.Konst == 0);
|
||||
assert(ValueType->GetRegCount() == from.RegCount);
|
||||
// Do it in-place, unless a local variable
|
||||
|
|
@ -2093,6 +2253,16 @@ ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
assert(Operand->ValueType->GetRegType() == REGT_INT);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
|
||||
if(from.Konst && from.RegType == REGT_INT)
|
||||
{ // this is needed here because the int const assign optimization returns a constant
|
||||
ExpEmit to;
|
||||
to.Konst = true;
|
||||
to.RegType = REGT_INT;
|
||||
to.RegNum = build->GetConstantInt(~build->FindConstantInt(from.RegNum));
|
||||
return to;
|
||||
}
|
||||
|
||||
from.Free(build);
|
||||
ExpEmit to(build, REGT_INT);
|
||||
assert(!from.Konst);
|
||||
|
|
@ -2164,6 +2334,16 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
|||
assert(Operand->ValueType == TypeBool);
|
||||
assert(ValueType == TypeBool || IsInteger()); // this may have been changed by an int cast.
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
|
||||
if(from.Konst && from.RegType == REGT_INT)
|
||||
{ // this is needed here because the int const assign optimization returns a constant
|
||||
ExpEmit to;
|
||||
to.Konst = true;
|
||||
to.RegType = REGT_INT;
|
||||
to.RegNum = build->GetConstantInt(!build->FindConstantInt(from.RegNum));
|
||||
return to;
|
||||
}
|
||||
|
||||
from.Free(build);
|
||||
ExpEmit to(build, REGT_INT);
|
||||
assert(!from.Konst);
|
||||
|
|
@ -2548,7 +2728,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
FArgumentList args;
|
||||
args.Push(Right);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
|
||||
Right = Base = nullptr;
|
||||
delete this;
|
||||
return call->Resolve(ctx);
|
||||
|
|
@ -2576,7 +2756,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
FArgumentList args;
|
||||
args.Push(Right);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
|
||||
auto call = new FxMemberFunctionCall(Base, NAME_Copy, std::move(args), ScriptPosition);
|
||||
Right = Base = nullptr;
|
||||
delete this;
|
||||
return call->Resolve(ctx);
|
||||
|
|
@ -3646,6 +3826,16 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
|
|||
delete left;
|
||||
left = x;
|
||||
}
|
||||
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
right = new FxTypeCast(right, TypeSInt32, true);
|
||||
SAFE_RESOLVE(right, ctx);
|
||||
}
|
||||
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
left = new FxTypeCast(left, TypeSInt32, true);
|
||||
SAFE_RESOLVE(left, ctx);
|
||||
}
|
||||
|
||||
if (left->ValueType == TypeString || right->ValueType == TypeString)
|
||||
{
|
||||
|
|
@ -3938,6 +4128,17 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
|||
delete left;
|
||||
left = x;
|
||||
}
|
||||
else if (left->IsNumeric() && right->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
right = new FxIntCast(right, true, true);
|
||||
SAFE_RESOLVE(right, ctx);
|
||||
}
|
||||
else if (right->IsNumeric() && left->ValueType == TypeTranslationID && ctx.Version < MakeVersion(4, 12))
|
||||
{
|
||||
left = new FxTypeCast(left, TypeSInt32, true);
|
||||
SAFE_RESOLVE(left, ctx);
|
||||
}
|
||||
|
||||
// Special cases: Compare strings and names with names, sounds, colors, state labels and class types.
|
||||
// These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison.
|
||||
if ((left->ValueType == TypeString || left->ValueType == TypeName) &&
|
||||
|
|
@ -4590,6 +4791,7 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build)
|
|||
else if (left->ValueType == TypeColor) cast = CAST_Co2S;
|
||||
else if (left->ValueType == TypeSpriteID) cast = CAST_SID2S;
|
||||
else if (left->ValueType == TypeTextureID) cast = CAST_TID2S;
|
||||
else if (left->ValueType == TypeTranslationID) cast = CAST_U2S;
|
||||
else if (op1.RegType == REGT_POINTER) cast = CAST_P2S;
|
||||
else if (op1.RegType == REGT_INT) cast = CAST_I2S;
|
||||
else assert(false && "Bad type for string concatenation");
|
||||
|
|
@ -4623,6 +4825,7 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build)
|
|||
else if (right->ValueType == TypeColor) cast = CAST_Co2S;
|
||||
else if (right->ValueType == TypeSpriteID) cast = CAST_SID2S;
|
||||
else if (right->ValueType == TypeTextureID) cast = CAST_TID2S;
|
||||
else if (right->ValueType == TypeTranslationID) cast = CAST_U2S;
|
||||
else if (op2.RegType == REGT_POINTER) cast = CAST_P2S;
|
||||
else if (op2.RegType == REGT_INT) cast = CAST_I2S;
|
||||
else assert(false && "Bad type for string concatenation");
|
||||
|
|
@ -5094,11 +5297,24 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
|
|||
ValueType = truex->ValueType;
|
||||
else if (falsex->IsPointer() && truex->ValueType == TypeNullPtr)
|
||||
ValueType = falsex->ValueType;
|
||||
// translation IDs need a bit of glue for compatibility and the 0 literal.
|
||||
else if (truex->IsInteger() && falsex->ValueType == TypeTranslationID)
|
||||
{
|
||||
truex = new FxTranslationCast(truex);
|
||||
truex = truex->Resolve(ctx);
|
||||
ValueType = ctx.Version < MakeVersion(4, 12, 0)? TypeSInt32 : TypeTranslationID;
|
||||
}
|
||||
else if (falsex->IsInteger() && truex->ValueType == TypeTranslationID)
|
||||
{
|
||||
falsex = new FxTranslationCast(falsex);
|
||||
falsex = falsex->Resolve(ctx);
|
||||
ValueType = ctx.Version < MakeVersion(4, 12, 0) ? TypeSInt32 : TypeTranslationID;
|
||||
}
|
||||
|
||||
else
|
||||
ValueType = TypeVoid;
|
||||
//else if (truex->ValueType != falsex->ValueType)
|
||||
|
||||
if (ValueType->GetRegType() == REGT_NIL)
|
||||
if (truex == nullptr || falsex == nullptr || ValueType->GetRegType() == REGT_NIL)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Incompatible types for ?: operator");
|
||||
delete this;
|
||||
|
|
@ -7986,7 +8202,7 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos)
|
||||
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_FunctionCall, pos)
|
||||
{
|
||||
MethodName = methodname;
|
||||
|
|
@ -8230,6 +8446,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
MethodName == NAME_Name ? TypeName :
|
||||
MethodName == NAME_SpriteID ? TypeSpriteID :
|
||||
MethodName == NAME_TextureID ? TypeTextureID :
|
||||
MethodName == NAME_TranslationID ? TypeTranslationID :
|
||||
MethodName == NAME_State ? TypeState :
|
||||
MethodName == NAME_Color ? TypeColor : (PType*)TypeSound;
|
||||
|
||||
|
|
@ -8412,7 +8629,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos)
|
||||
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_MemberFunctionCall, pos)
|
||||
{
|
||||
Self = self;
|
||||
|
|
@ -8957,7 +9174,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
if (a->IsMap())
|
||||
{
|
||||
// Copy and Move must turn their parameter into a pointer to the backing struct type.
|
||||
auto o = static_cast<PMapIterator*>(a->ValueType);
|
||||
auto o = static_cast<PMap*>(a->ValueType);
|
||||
auto backingtype = o->BackingType;
|
||||
if (mapKeyType != o->KeyType || mapValueType != o->ValueType)
|
||||
{
|
||||
|
|
@ -11165,12 +11382,14 @@ ExpEmit FxForLoop::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Code(code)
|
||||
FxForEachLoop::FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxLoopStatement(EFX_ForEachLoop, pos), loopVarName(vn), Array(arrayvar), Array2(arrayvar2), Array3(arrayvar3), Array4(arrayvar4), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Array != nullptr) Array->NeedResult = false;
|
||||
if (Array2 != nullptr) Array2->NeedResult = false;
|
||||
if (Array3 != nullptr) Array3->NeedResult = false;
|
||||
if (Array4 != nullptr) Array4->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
|
|
@ -11178,57 +11397,347 @@ FxForEachLoop::~FxForEachLoop()
|
|||
{
|
||||
SAFE_DELETE(Array);
|
||||
SAFE_DELETE(Array2);
|
||||
SAFE_DELETE(Array3);
|
||||
SAFE_DELETE(Array4);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool IsGameSpecificForEachLoop(FxForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop *);
|
||||
|
||||
FxExpression* FxForEachLoop::DoResolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Array, ctx);
|
||||
SAFE_RESOLVE(Array2, ctx);
|
||||
SAFE_RESOLVE(Array3, ctx);
|
||||
SAFE_RESOLVE(Array4, ctx);
|
||||
|
||||
// Instead of writing a new code generator for this, convert this into
|
||||
//
|
||||
// int @size = array.Size();
|
||||
// for(int @i = 0; @i < @size; @i++)
|
||||
// {
|
||||
// let var = array[i];
|
||||
// body
|
||||
// }
|
||||
// and let the existing 'for' loop code sort out the rest.
|
||||
|
||||
FName sizevar = "@size";
|
||||
FName itvar = "@i";
|
||||
FArgumentList al;
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, al, ScriptPosition);
|
||||
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
|
||||
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
|
||||
block->Add(size);
|
||||
block->Add(it);
|
||||
if(Array->ValueType->isMap() || Array->ValueType->isMapIterator())
|
||||
{
|
||||
auto mapLoop = new FxTwoArgForEachLoop(NAME_None, loopVarName, Array, Array2, Array3, Array4, Code, ScriptPosition);
|
||||
Array = Array2 = Array3 = Array4 = Code = nullptr;
|
||||
delete this;
|
||||
return mapLoop->Resolve(ctx);
|
||||
}
|
||||
else if(IsGameSpecificForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Instead of writing a new code generator for this, convert this into
|
||||
//
|
||||
// int @size = array.Size();
|
||||
// for(int @i = 0; @i < @size; @i++)
|
||||
// {
|
||||
// let var = array[i];
|
||||
// body
|
||||
// }
|
||||
// and let the existing 'for' loop code sort out the rest.
|
||||
|
||||
auto cit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto csiz = new FxLocalVariable(size, ScriptPosition);
|
||||
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
|
||||
FName sizevar = "@size";
|
||||
FName itvar = "@i";
|
||||
|
||||
auto iit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto bump = new FxPreIncrDecr(iit, TK_Incr);
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
auto arraysize = new FxMemberFunctionCall(Array, NAME_Size, {}, ScriptPosition);
|
||||
auto size = new FxLocalVariableDeclaration(TypeSInt32, sizevar, arraysize, 0, ScriptPosition);
|
||||
auto it = new FxLocalVariableDeclaration(TypeSInt32, itvar, new FxConstant(0, ScriptPosition), 0, ScriptPosition);
|
||||
block->Add(size);
|
||||
block->Add(it);
|
||||
|
||||
auto ait = new FxLocalVariable(it, ScriptPosition);
|
||||
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
|
||||
auto cit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto csiz = new FxLocalVariable(size, ScriptPosition);
|
||||
auto comp = new FxCompareRel('<', cit, csiz); // new FxIdentifier(itvar, ScriptPosition), new FxIdentifier(sizevar, ScriptPosition));
|
||||
|
||||
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
|
||||
auto body = new FxCompoundStatement(ScriptPosition);
|
||||
body->Add(assign);
|
||||
body->Add(Code);
|
||||
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
|
||||
block->Add(forloop);
|
||||
Array2 = Array = nullptr;
|
||||
Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
auto iit = new FxLocalVariable(it, ScriptPosition);
|
||||
auto bump = new FxPreIncrDecr(iit, TK_Incr);
|
||||
|
||||
auto ait = new FxLocalVariable(it, ScriptPosition);
|
||||
auto access = new FxArrayElement(Array2, ait, true); // Note: Array must be a separate copy because these nodes cannot share the same element.
|
||||
|
||||
auto assign = new FxLocalVariableDeclaration(TypeAuto, loopVarName, access, 0, ScriptPosition);
|
||||
auto body = new FxCompoundStatement(ScriptPosition);
|
||||
body->Add(assign);
|
||||
body->Add(Code);
|
||||
auto forloop = new FxForLoop(nullptr, comp, bump, body, ScriptPosition);
|
||||
block->Add(forloop);
|
||||
Array2 = Array = nullptr;
|
||||
Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxMapForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTwoArgForEachLoop::FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_TwoArgForEachLoop,pos), keyVarName(kv), valueVarName(vv), MapExpr(mapexpr), MapExpr2(mapexpr2), MapExpr3(mapexpr3), MapExpr4(mapexpr4), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (MapExpr != nullptr) MapExpr->NeedResult = false;
|
||||
if (MapExpr2 != nullptr) MapExpr2->NeedResult = false;
|
||||
if (MapExpr3 != nullptr) MapExpr3->NeedResult = false;
|
||||
if (MapExpr4 != nullptr) MapExpr4->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxTwoArgForEachLoop::~FxTwoArgForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(MapExpr);
|
||||
SAFE_DELETE(MapExpr2);
|
||||
SAFE_DELETE(MapExpr3);
|
||||
SAFE_DELETE(MapExpr4);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificTwoArgForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificTwoArgForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop *);
|
||||
|
||||
FxExpression *FxTwoArgForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(MapExpr, ctx);
|
||||
SAFE_RESOLVE(MapExpr2, ctx);
|
||||
SAFE_RESOLVE(MapExpr3, ctx);
|
||||
SAFE_RESOLVE(MapExpr4, ctx);
|
||||
|
||||
bool is_iterator = false;
|
||||
|
||||
if(IsGameSpecificTwoArgForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificTwoArgForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else if(!(MapExpr->ValueType->isMap() || (is_iterator = MapExpr->ValueType->isMapIterator())))
|
||||
{
|
||||
if(HasGameSpecificTwoArgForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be %s a map, or a map iterator, but is a %s", GetGameSpecificTwoArgForEachLoopTypeNames(), MapExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( k, v : m ) - 'm' must be a map or a map iterator, but is a %s", MapExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if(valueVarName == NAME_None)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "missing value for foreach( k, v : m )");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
auto valType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->ValueType : static_cast<PMap*>(MapExpr->ValueType)->ValueType;
|
||||
auto keyType = is_iterator ? static_cast<PMapIterator*>(MapExpr->ValueType)->KeyType : static_cast<PMap*>(MapExpr->ValueType)->KeyType;
|
||||
|
||||
auto v = new FxLocalVariableDeclaration(valType, valueVarName, nullptr, 0, ScriptPosition);
|
||||
block->Add(v);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
auto k = new FxLocalVariableDeclaration(keyType, keyVarName, nullptr, 0, ScriptPosition);
|
||||
block->Add(k);
|
||||
}
|
||||
|
||||
|
||||
if(MapExpr->ValueType->isMapIterator())
|
||||
{
|
||||
/*
|
||||
{
|
||||
KeyType k;
|
||||
ValueType v;
|
||||
if(it.ReInit()) while(it.Next())
|
||||
{
|
||||
k = it.GetKey();
|
||||
v = it.GetValue();
|
||||
body
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
auto inner_block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr, "GetKey", {}, ScriptPosition), true));
|
||||
}
|
||||
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(MapExpr2, "GetValue", {}, ScriptPosition), true));
|
||||
inner_block->Add(Code);
|
||||
|
||||
auto reInit = new FxMemberFunctionCall(MapExpr3, "ReInit", {}, ScriptPosition);
|
||||
block->Add(new FxIfStatement(reInit, new FxWhileLoop(new FxMemberFunctionCall(MapExpr4, "Next", {}, ScriptPosition), inner_block, ScriptPosition), nullptr, ScriptPosition));
|
||||
|
||||
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
{
|
||||
KeyType k;
|
||||
ValueType v;
|
||||
MapIterator<KeyType, ValueType> @it;
|
||||
@it.Init(map);
|
||||
while(@it.Next())
|
||||
{
|
||||
k = @it.GetKey();
|
||||
v = @it.GetValue();
|
||||
body
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
PType * itType = NewMapIterator(keyType, valType);
|
||||
auto it = new FxLocalVariableDeclaration(itType, "@it", nullptr, 0, ScriptPosition);
|
||||
block->Add(it);
|
||||
|
||||
FArgumentList al_map;
|
||||
al_map.Push(MapExpr);
|
||||
|
||||
block->Add(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Init", std::move(al_map), ScriptPosition));
|
||||
|
||||
auto inner_block = new FxCompoundStatement(ScriptPosition);
|
||||
|
||||
if(keyVarName != NAME_None)
|
||||
{
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(keyVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetKey", {}, ScriptPosition), true));
|
||||
}
|
||||
inner_block->Add(new FxAssign(new FxIdentifier(valueVarName, ScriptPosition), new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "GetValue", {}, ScriptPosition), true));
|
||||
inner_block->Add(Code);
|
||||
|
||||
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
|
||||
|
||||
delete MapExpr2;
|
||||
delete MapExpr3;
|
||||
delete MapExpr4;
|
||||
MapExpr = MapExpr2 = MapExpr3 = MapExpr4 = Code = nullptr;
|
||||
delete this;
|
||||
return block->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxThreeArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxThreeArgForEachLoop::FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_ThreeArgForEachLoop, pos), varVarName(vv), posVarName(pv), flagsVarName(fv), BlockIteratorExpr(blockiteartorexpr), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (BlockIteratorExpr != nullptr) BlockIteratorExpr->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxThreeArgForEachLoop::~FxThreeArgForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(BlockIteratorExpr);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificThreeArgForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificThreeArgForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop *);
|
||||
|
||||
FxExpression *FxThreeArgForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(BlockIteratorExpr, ctx);
|
||||
|
||||
|
||||
if(IsGameSpecificThreeArgForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificThreeArgForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//put any non-game-specific typed for-each loops here
|
||||
}
|
||||
|
||||
if(HasGameSpecificThreeArgForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - 'it' must be % but is a %s", GetGameSpecificThreeArgForEachLoopTypeNames(), BlockIteratorExpr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach( a, b, c : it ) - three-arg foreach loops not supported");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxCastForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxTypedForEachLoop::FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos)
|
||||
: FxExpression(EFX_TypedForEachLoop, pos), className(cv), varName(vv), Expr(castiteartorexpr), Code(code)
|
||||
{
|
||||
ValueType = TypeVoid;
|
||||
if (Expr != nullptr) Expr->NeedResult = false;
|
||||
if (Code != nullptr) Code->NeedResult = false;
|
||||
}
|
||||
|
||||
FxTypedForEachLoop::~FxTypedForEachLoop()
|
||||
{
|
||||
SAFE_DELETE(Expr);
|
||||
SAFE_DELETE(Code);
|
||||
}
|
||||
|
||||
extern bool HasGameSpecificTypedForEachLoopTypeNames();
|
||||
extern const char * GetGameSpecificTypedForEachLoopTypeNames();
|
||||
extern bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
|
||||
extern FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop *);
|
||||
|
||||
FxExpression *FxTypedForEachLoop::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(Expr, ctx);
|
||||
|
||||
if(IsGameSpecificTypedForEachLoop(this))
|
||||
{
|
||||
return ResolveGameSpecificTypedForEachLoop(this)->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//put any non-game-specific typed for-each loops here
|
||||
}
|
||||
|
||||
if(HasGameSpecificTypedForEachLoopTypeNames())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be % but is a %s",GetGameSpecificTypedForEachLoopTypeNames(), Expr->ValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - typed foreach loops not supported");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
@ -12071,8 +12580,7 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
|
|||
if (IsDynamicArray())
|
||||
{
|
||||
auto stackVar = new FxStackVariable(ValueType, StackOffset, ScriptPosition);
|
||||
FArgumentList argsList;
|
||||
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", argsList, ScriptPosition);
|
||||
clearExpr = new FxMemberFunctionCall(stackVar, "Clear", {}, ScriptPosition);
|
||||
SAFE_RESOLVE(clearExpr, ctx);
|
||||
}
|
||||
|
||||
|
|
@ -12390,10 +12898,9 @@ FxExpression *FxLocalArrayDeclaration::Resolve(FCompileContext &ctx)
|
|||
else
|
||||
{
|
||||
FArgumentList argsList;
|
||||
argsList.Clear();
|
||||
argsList.Push(v);
|
||||
|
||||
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, argsList, (const FScriptPosition) v->ScriptPosition);
|
||||
FxExpression *funcCall = new FxMemberFunctionCall(stackVar, NAME_Push, std::move(argsList), (const FScriptPosition) v->ScriptPosition);
|
||||
SAFE_RESOLVE(funcCall, ctx);
|
||||
|
||||
v = funcCall;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "types.h"
|
||||
#include "vmintern.h"
|
||||
#include "c_cvars.h"
|
||||
#include "palettecontainer.h"
|
||||
|
||||
struct FState; // needed for FxConstant. Maybe move the state constructor to a subclass later?
|
||||
|
||||
|
|
@ -232,6 +233,7 @@ enum EFxType
|
|||
EFX_StringCast,
|
||||
EFX_ColorCast,
|
||||
EFX_SoundCast,
|
||||
EFX_TranslationCast,
|
||||
EFX_TypeCast,
|
||||
EFX_PlusSign,
|
||||
EFX_MinusSign,
|
||||
|
|
@ -273,6 +275,9 @@ enum EFxType
|
|||
EFX_DoWhileLoop,
|
||||
EFX_ForLoop,
|
||||
EFX_ForEachLoop,
|
||||
EFX_TwoArgForEachLoop,
|
||||
EFX_ThreeArgForEachLoop,
|
||||
EFX_TypedForEachLoop,
|
||||
EFX_JumpStatement,
|
||||
EFX_ReturnStatement,
|
||||
EFX_ClassTypeCast,
|
||||
|
|
@ -507,6 +512,13 @@ public:
|
|||
isresolved = true;
|
||||
}
|
||||
|
||||
FxConstant(FTranslationID state, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos)
|
||||
{
|
||||
value.Int = state.index();
|
||||
ValueType = value.Type = TypeTranslationID;
|
||||
isresolved = true;
|
||||
}
|
||||
|
||||
FxConstant(VMFunction* state, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos)
|
||||
{
|
||||
value.pointer = state;
|
||||
|
|
@ -715,6 +727,19 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
class FxTranslationCast : public FxExpression
|
||||
{
|
||||
FxExpression* basex;
|
||||
|
||||
public:
|
||||
|
||||
FxTranslationCast(FxExpression* x);
|
||||
~FxTranslationCast();
|
||||
FxExpression* Resolve(FCompileContext&);
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder* build);
|
||||
};
|
||||
|
||||
class FxFontCast : public FxExpression
|
||||
{
|
||||
FxExpression *basex;
|
||||
|
|
@ -1599,7 +1624,7 @@ public:
|
|||
FName MethodName;
|
||||
FArgumentList ArgList;
|
||||
|
||||
FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos);
|
||||
FxFunctionCall(FName methodname, FName rngname, FArgumentList &&args, const FScriptPosition &pos);
|
||||
~FxFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
|
@ -1616,10 +1641,11 @@ class FxMemberFunctionCall : public FxExpression
|
|||
FxExpression *Self;
|
||||
FName MethodName;
|
||||
FArgumentList ArgList;
|
||||
bool ResolveSelf;
|
||||
|
||||
public:
|
||||
|
||||
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos);
|
||||
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &&args, const FScriptPosition &pos);
|
||||
~FxMemberFunctionCall();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
|
@ -2047,17 +2073,83 @@ public:
|
|||
|
||||
class FxForEachLoop : public FxLoopStatement
|
||||
{
|
||||
public:
|
||||
FName loopVarName;
|
||||
FxExpression* Array;
|
||||
FxExpression* Array2;
|
||||
FxExpression* Array3;
|
||||
FxExpression* Array4;
|
||||
FxExpression* Code;
|
||||
|
||||
public:
|
||||
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* code, const FScriptPosition& pos);
|
||||
FxForEachLoop(FName vn, FxExpression* arrayvar, FxExpression* arrayvar2, FxExpression* arrayvar3, FxExpression* arrayvar4, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxForEachLoop();
|
||||
FxExpression* DoResolve(FCompileContext&);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxTwoArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxTwoArgForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName keyVarName;
|
||||
FName valueVarName;
|
||||
FxExpression* MapExpr;
|
||||
FxExpression* MapExpr2;
|
||||
FxExpression* MapExpr3;
|
||||
FxExpression* MapExpr4;
|
||||
FxExpression* Code;
|
||||
|
||||
FxTwoArgForEachLoop(FName kv, FName vv, FxExpression* mapexpr, FxExpression* mapexpr2, FxExpression* mapexpr3, FxExpression* mapexpr4, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxTwoArgForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxThreeArgForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxThreeArgForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName varVarName;
|
||||
FName posVarName;
|
||||
FName flagsVarName;
|
||||
FxExpression* BlockIteratorExpr;
|
||||
FxExpression* Code;
|
||||
|
||||
FxThreeArgForEachLoop(FName vv, FName pv, FName fv, FxExpression* blockiteartorexpr, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxThreeArgForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxTypedForEachLoop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxTypedForEachLoop : public FxExpression
|
||||
{
|
||||
public:
|
||||
FName className;
|
||||
FName varName;
|
||||
FxExpression* Expr;
|
||||
FxExpression* Code;
|
||||
|
||||
FxTypedForEachLoop(FName cv, FName vv, FxExpression* castiteartorexpr, FxExpression* code, const FScriptPosition& pos);
|
||||
~FxTypedForEachLoop();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxJumpStatement
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@
|
|||
|
||||
CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||
|
||||
EXTERN_CVAR(Bool, vm_jit)
|
||||
EXTERN_CVAR(Bool, vm_jit_aot)
|
||||
|
||||
struct VMRemap
|
||||
{
|
||||
uint8_t altOp, kReg, kType;
|
||||
|
|
@ -290,6 +293,24 @@ unsigned VMFunctionBuilder::GetConstantAddress(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// VMFunctionBuilder :: FindConstantInt
|
||||
//
|
||||
// Returns a constant register initialized with the given value.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int VMFunctionBuilder::FindConstantInt(unsigned index)
|
||||
{
|
||||
if(IntConstantList.Size() < index)
|
||||
{
|
||||
return IntConstantList[index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// VMFunctionBuilder :: AllocConstants*
|
||||
|
|
@ -298,7 +319,7 @@ unsigned VMFunctionBuilder::GetConstantAddress(void *ptr)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values)
|
||||
unsigned VMFunctionBuilder::AllocConstantsInt(unsigned int count, int *values)
|
||||
{
|
||||
unsigned addr = IntConstantList.Reserve(count);
|
||||
memcpy(&IntConstantList[addr], values, count * sizeof(int));
|
||||
|
|
@ -309,7 +330,7 @@ unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values)
|
|||
return addr;
|
||||
}
|
||||
|
||||
unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values)
|
||||
unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned int count, double *values)
|
||||
{
|
||||
unsigned addr = FloatConstantList.Reserve(count);
|
||||
memcpy(&FloatConstantList[addr], values, count * sizeof(double));
|
||||
|
|
@ -320,7 +341,7 @@ unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values)
|
|||
return addr;
|
||||
}
|
||||
|
||||
unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs)
|
||||
unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned int count, void **ptrs)
|
||||
{
|
||||
unsigned addr = AddressConstantList.Reserve(count);
|
||||
memcpy(&AddressConstantList[addr], ptrs, count * sizeof(void *));
|
||||
|
|
@ -331,7 +352,7 @@ unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs)
|
|||
return addr;
|
||||
}
|
||||
|
||||
unsigned VMFunctionBuilder::AllocConstantsString(unsigned count, FString *ptrs)
|
||||
unsigned VMFunctionBuilder::AllocConstantsString(unsigned int count, FString *ptrs)
|
||||
{
|
||||
unsigned addr = StringConstantList.Reserve(count);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
|
|
@ -910,6 +931,13 @@ void FFunctionBuildList::Build()
|
|||
disasmdump.Write(sfunc, item.PrintableName);
|
||||
|
||||
sfunc->Unsafe = ctx.Unsafe;
|
||||
|
||||
#if HAVE_VM_JIT
|
||||
if(vm_jit && vm_jit_aot)
|
||||
{
|
||||
sfunc->JitCompile();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
|
|
@ -1076,8 +1104,6 @@ void FunctionCallEmitter::AddParameterStringConst(const FString &konst)
|
|||
});
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Bool, vm_jit)
|
||||
|
||||
ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray<ExpEmit> *ReturnRegs)
|
||||
{
|
||||
unsigned paramcount = 0;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ public:
|
|||
unsigned GetConstantAddress(void *ptr);
|
||||
unsigned GetConstantString(FString str);
|
||||
|
||||
int FindConstantInt(unsigned index);
|
||||
//double FindConstantFloat(unsigned index);
|
||||
//void * FindConstantAddress(unsigned index);
|
||||
//const FString& FindConstantString(unsigned index);
|
||||
|
||||
unsigned AllocConstantsInt(unsigned int count, int *values);
|
||||
unsigned AllocConstantsFloat(unsigned int count, double *values);
|
||||
unsigned AllocConstantsAddress(unsigned int count, void **ptrs);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@
|
|||
#include "printf.h"
|
||||
#include "textureid.h"
|
||||
#include "maps.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "texturemanager.h"
|
||||
#include "i_interface.h"
|
||||
|
||||
|
||||
FTypeTable TypeTable;
|
||||
|
|
@ -58,6 +61,7 @@ PName *TypeName;
|
|||
PSound *TypeSound;
|
||||
PColor *TypeColor;
|
||||
PTextureID *TypeTextureID;
|
||||
PTranslationID* TypeTranslationID;
|
||||
PSpriteID *TypeSpriteID;
|
||||
PStatePointer *TypeState;
|
||||
PPointer *TypeFont;
|
||||
|
|
@ -322,6 +326,7 @@ void PType::StaticInit()
|
|||
TypeTable.AddType(TypeNullPtr = new PPointer, NAME_Pointer);
|
||||
TypeTable.AddType(TypeSpriteID = new PSpriteID, NAME_SpriteID);
|
||||
TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID);
|
||||
TypeTable.AddType(TypeTranslationID = new PTranslationID, NAME_TranslationID);
|
||||
|
||||
TypeVoidPtr = NewPointer(TypeVoid, false);
|
||||
TypeRawFunction = new PPointer;
|
||||
|
|
@ -1321,6 +1326,48 @@ bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
|||
return true;
|
||||
}
|
||||
|
||||
/* PTranslationID ******************************************************************/
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PTranslationID Default Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PTranslationID::PTranslationID()
|
||||
: PInt(sizeof(FTranslationID), true, false)
|
||||
{
|
||||
mDescriptiveName = "TranslationID";
|
||||
Flags |= TYPE_IntNotInt;
|
||||
static_assert(sizeof(FTranslationID) == alignof(FTranslationID), "TranslationID not properly aligned");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PTranslationID :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PTranslationID::WriteValue(FSerializer& ar, const char* key, const void* addr) const
|
||||
{
|
||||
FTranslationID val = *(FTranslationID*)addr;
|
||||
ar(key, val);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PTranslationID :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PTranslationID::ReadValue(FSerializer& ar, const char* key, void* addr) const
|
||||
{
|
||||
FTranslationID val;
|
||||
ar(key, val);
|
||||
*(FTranslationID*)addr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* PSound *****************************************************************/
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -1614,7 +1661,8 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
loadOp = OP_LP;
|
||||
storeOp = OP_SP;
|
||||
Flags |= TYPE_ClassPointer;
|
||||
mVersion = restrict->VMType->mVersion;
|
||||
if (restrict) mVersion = restrict->VMType->mVersion;
|
||||
else mVersion = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -2504,9 +2552,63 @@ static void PMapValueWriter(FSerializer &ar, const M *map, const PMap *m)
|
|||
}
|
||||
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
|
||||
{
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
|
||||
{
|
||||
if(m->KeyType == TypeName)
|
||||
{
|
||||
m->ValueType->WriteValue(ar,FName(ENamedName(p->Key)).GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(m->KeyType == TypeSound)
|
||||
{
|
||||
m->ValueType->WriteValue(ar,soundEngine->GetSoundName(FSoundID::fromInt(p->Key)),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(m->KeyType == TypeTextureID)
|
||||
{
|
||||
if(!!(p->Key & 0x8000000))
|
||||
{ // invalid
|
||||
m->ValueType->WriteValue(ar,"invalid",static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else if(p->Key == 0 || p->Key >= TexMan.NumTextures())
|
||||
{ // null
|
||||
m->ValueType->WriteValue(ar,"null",static_cast<const void *>(&p->Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
FTextureID tid;
|
||||
tid.SetIndex(p->Key);
|
||||
FGameTexture *tex = TexMan.GetGameTexture(tid);
|
||||
int lump = tex->GetSourceLump();
|
||||
unsigned useType = static_cast<unsigned>(tex->GetUseType());
|
||||
|
||||
FString name;
|
||||
|
||||
if (TexMan.GetLinkedTexture(lump) == tex)
|
||||
{
|
||||
name = fileSystem.GetFileFullName(lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = tex->GetName().GetChars();
|
||||
}
|
||||
|
||||
name.AppendFormat(":%u",useType);
|
||||
|
||||
m->ValueType->WriteValue(ar,name.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // bool/color/enum/sprite/translationID
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FString key;
|
||||
key.Format("%u",p->Key);
|
||||
m->ValueType->WriteValue(ar,key.GetChars(),static_cast<const void *>(&p->Value));
|
||||
}
|
||||
}
|
||||
//else unknown key type
|
||||
}
|
||||
|
|
@ -2539,20 +2641,85 @@ static bool PMapValueReader(FSerializer &ar, M *map, const PMap *m)
|
|||
const char * k;
|
||||
while((k = ar.GetKey()))
|
||||
{
|
||||
typename M::ValueType * val;
|
||||
typename M::ValueType * val = nullptr;
|
||||
if constexpr(std::is_same_v<typename M::KeyType,FString>)
|
||||
{
|
||||
val = &map->InsertNew(k);
|
||||
}
|
||||
else if constexpr(std::is_same_v<typename M::KeyType,uint32_t>)
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
if(m->KeyType->Flags & 8 /*TYPE_IntNotInt*/)
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
if(m->KeyType == TypeName)
|
||||
{
|
||||
val = &map->InsertNew(FName(k).GetIndex());
|
||||
}
|
||||
else if(m->KeyType == TypeSound)
|
||||
{
|
||||
val = &map->InsertNew(S_FindSound(k).index());
|
||||
}
|
||||
else if(m->KeyType == TypeTextureID)
|
||||
{
|
||||
FString s(k);
|
||||
FTextureID tex;
|
||||
if(s.Compare("invalid") == 0)
|
||||
{
|
||||
tex.SetInvalid();
|
||||
}
|
||||
else if(s.Compare("null") == 0)
|
||||
{
|
||||
tex.SetNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
ptrdiff_t sep = s.LastIndexOf(":");
|
||||
if(sep < 0)
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
FString texName = s.Left(sep);
|
||||
FString useType = s.Mid(sep + 1);
|
||||
|
||||
tex = TexMan.GetTextureID(texName.GetChars(), (ETextureType) useType.ToULong());
|
||||
}
|
||||
val = &map->InsertNew(tex.GetIndex());
|
||||
}
|
||||
else if(m->KeyType == TypeTranslationID)
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
int v = s.ToULong();
|
||||
|
||||
if (sysCallbacks.RemapTranslation) v = sysCallbacks.RemapTranslation(FTranslationID::fromInt(v)).index();
|
||||
|
||||
val = &map->InsertNew(v);
|
||||
}
|
||||
else
|
||||
{ // bool/color/enum/sprite
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FString s(k);
|
||||
if(!s.IsInt())
|
||||
{
|
||||
ar.EndObject();
|
||||
return false;
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
val = &map->InsertNew(static_cast<uint32_t>(s.ToULong()));
|
||||
}
|
||||
if (!m->ValueType->ReadValue(ar,nullptr,static_cast<void*>(val)))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -383,6 +383,15 @@ public:
|
|||
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
|
||||
};
|
||||
|
||||
class PTranslationID : public PInt
|
||||
{
|
||||
public:
|
||||
PTranslationID();
|
||||
|
||||
void WriteValue(FSerializer& ar, const char* key, const void* addr) const override;
|
||||
bool ReadValue(FSerializer& ar, const char* key, void* addr) const override;
|
||||
};
|
||||
|
||||
class PColor : public PInt
|
||||
{
|
||||
public:
|
||||
|
|
@ -712,6 +721,7 @@ extern PName *TypeName;
|
|||
extern PSound *TypeSound;
|
||||
extern PColor *TypeColor;
|
||||
extern PTextureID *TypeTextureID;
|
||||
extern PTranslationID* TypeTranslationID;
|
||||
extern PSpriteID *TypeSpriteID;
|
||||
extern PStruct* TypeVector2;
|
||||
extern PStruct* TypeVector3;
|
||||
|
|
|
|||
|
|
@ -983,6 +983,53 @@ static void PrintArrayIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
|||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintTwoArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_TwoArgIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("map-iteration-stmt");
|
||||
PrintVarName(out, inode->ItKey);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItValue);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItMap);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintThreeArgIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_ThreeArgIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("block-iteration-stmt");
|
||||
PrintVarName(out, inode->ItVar);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItPos);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItFlags);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItBlock);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintTypedIterationStmt(FLispString &out, const ZCC_TreeNode *node)
|
||||
{
|
||||
auto inode = (ZCC_TypedIterationStmt *)node;
|
||||
out.Break();
|
||||
out.Open("cast-iteration-stmt");
|
||||
PrintVarName(out, inode->ItType);
|
||||
out.Break();
|
||||
PrintVarName(out, inode->ItVar);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->ItExpr);
|
||||
out.Break();
|
||||
PrintNodes(out, inode->LoopStatement);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static const NodePrinterFunc TreeNodePrinter[] =
|
||||
{
|
||||
PrintIdentifier,
|
||||
|
|
@ -1050,6 +1097,9 @@ static const NodePrinterFunc TreeNodePrinter[] =
|
|||
PrintMixinDef,
|
||||
PrintMixinStmt,
|
||||
PrintArrayIterationStmt,
|
||||
PrintTwoArgIterationStmt,
|
||||
PrintThreeArgIterationStmt,
|
||||
PrintTypedIterationStmt,
|
||||
};
|
||||
|
||||
FString ZCC_PrintAST(const ZCC_TreeNode *root)
|
||||
|
|
|
|||
|
|
@ -1956,6 +1956,9 @@ statement(X) ::= expression_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/
|
|||
statement(X) ::= selection_statement(X).
|
||||
statement(X) ::= iteration_statement(X).
|
||||
statement(X) ::= array_iteration_statement(X).
|
||||
statement(X) ::= two_arg_iteration_statement(X).
|
||||
statement(X) ::= three_arg_iteration_statement(X).
|
||||
statement(X) ::= typed_iteration_statement(X).
|
||||
statement(X) ::= jump_statement(X).
|
||||
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||
statement(X) ::= assign_decl_statement(A) SEMICOLON.{ X = A; /*X-overwrites-A*/ }
|
||||
|
|
@ -2125,6 +2128,43 @@ array_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(IN) COLON expr(
|
|||
X = iter;
|
||||
}
|
||||
|
||||
%type two_arg_iteration_statement{ZCC_Statement *}
|
||||
|
||||
two_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(KEY) COMMA variable_name(VAL) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(TwoArgIterationStmt, iter, T);
|
||||
iter->ItKey = KEY;
|
||||
iter->ItValue = VAL;
|
||||
iter->ItMap = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
%type three_arg_iteration_statement{ZCC_Statement *}
|
||||
|
||||
three_arg_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(VAR) COMMA variable_name(POS) COMMA variable_name(FLAGS) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(ThreeArgIterationStmt, iter, T);
|
||||
iter->ItVar = VAR;
|
||||
iter->ItPos = POS;
|
||||
iter->ItFlags = FLAGS;
|
||||
iter->ItBlock = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
%type typed_iteration_statement{ZCC_Statement *}
|
||||
|
||||
typed_iteration_statement(X) ::= FOREACH(T) LPAREN variable_name(TYPE) variable_name(VAR) COLON expr(EX) RPAREN statement(ST).
|
||||
{
|
||||
NEW_AST_NODE(TypedIterationStmt, iter, T);
|
||||
iter->ItType = TYPE;
|
||||
iter->ItVar = VAR;
|
||||
iter->ItExpr = EX;
|
||||
iter->LoopStatement = ST;
|
||||
X = iter;
|
||||
}
|
||||
|
||||
while_or_until(X) ::= WHILE(T).
|
||||
{
|
||||
X.Int = ZCC_WHILE;
|
||||
|
|
|
|||
|
|
@ -1886,6 +1886,12 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
|
|||
retval = TypeTextureID;
|
||||
break;
|
||||
|
||||
case NAME_TranslationID:
|
||||
retval = TypeTranslationID;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
default:
|
||||
retval = ResolveUserType(btype, btype->UserType, outertype ? &outertype->Symbols : nullptr, false);
|
||||
break;
|
||||
|
|
@ -2993,12 +2999,12 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
{
|
||||
case AST_ExprID:
|
||||
// The function name is a simple identifier.
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
|
||||
case AST_ExprMemberAccess:
|
||||
{
|
||||
auto ema = static_cast<ZCC_ExprMemberAccess *>(fcall->Function);
|
||||
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxMemberFunctionCall(ConvertNode(ema->Left, true), ema->Right, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
}
|
||||
|
||||
case AST_ExprBinary:
|
||||
|
|
@ -3008,7 +3014,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
auto binary = static_cast<ZCC_ExprBinary *>(fcall->Function);
|
||||
if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID)
|
||||
{
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast);
|
||||
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, std::move(ConvertNodeList(args, fcall->Parameters)), *ast);
|
||||
}
|
||||
}
|
||||
// fall through if this isn't an array access node.
|
||||
|
|
@ -3382,10 +3388,45 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
|
|||
auto iter = static_cast<ZCC_ArrayIterationStmt*>(ast);
|
||||
auto var = iter->ItName->Name;
|
||||
FxExpression* const itArray = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray2 = ConvertNode(iter->ItArray); // the handler needs two copies of this - here's the easiest place to create them.
|
||||
FxExpression* const itArray2 = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray3 = ConvertNode(iter->ItArray);
|
||||
FxExpression* const itArray4 = ConvertNode(iter->ItArray); // the handler needs copies of this - here's the easiest place to create them.
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, body, *ast);
|
||||
return new FxForEachLoop(iter->ItName->Name, itArray, itArray2, itArray3, itArray4, body, *ast);
|
||||
}
|
||||
|
||||
case AST_TwoArgIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_TwoArgIterationStmt*>(ast);
|
||||
auto key = iter->ItKey->Name;
|
||||
auto var = iter->ItValue->Name;
|
||||
FxExpression* const itMap = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap2 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap3 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const itMap4 = ConvertNode(iter->ItMap);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxTwoArgForEachLoop(key, var, itMap, itMap2, itMap3, itMap4, body, *ast);
|
||||
}
|
||||
|
||||
case AST_ThreeArgIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_ThreeArgIterationStmt*>(ast);
|
||||
auto var = iter->ItVar->Name;
|
||||
auto pos = iter->ItPos->Name;
|
||||
auto flags = iter->ItFlags->Name;
|
||||
FxExpression* const itBlock = ConvertNode(iter->ItBlock);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxThreeArgForEachLoop(var, pos, flags, itBlock, body, *ast);
|
||||
}
|
||||
|
||||
case AST_TypedIterationStmt:
|
||||
{
|
||||
auto iter = static_cast<ZCC_TypedIterationStmt*>(ast);
|
||||
auto cls = iter->ItType->Name;
|
||||
auto var = iter->ItVar->Name;
|
||||
FxExpression* const itExpr = ConvertNode(iter->ItExpr);
|
||||
FxExpression* const body = ConvertImplicitScopeNode(ast, iter->LoopStatement);
|
||||
return new FxTypedForEachLoop(cls, var, itExpr, body, *ast);
|
||||
}
|
||||
|
||||
case AST_IterationStmt:
|
||||
|
|
|
|||
|
|
@ -1177,6 +1177,46 @@ ZCC_TreeNode *TreeNodeDeepCopy_Internal(ZCC_AST *ast, ZCC_TreeNode *orig, bool c
|
|||
break;
|
||||
}
|
||||
|
||||
case AST_TwoArgIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(TwoArgIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItKey = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItKey, true, copiedNodesList));
|
||||
copy->ItValue = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItValue, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItMap = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItMap, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_ThreeArgIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(ThreeArgIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
|
||||
copy->ItPos = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItPos, true, copiedNodesList));
|
||||
copy->ItFlags = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItFlags, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItBlock = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItBlock, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_TypedIterationStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(TypedIterationStmt);
|
||||
|
||||
// ZCC_TwoArgIterationStmt
|
||||
copy->ItType = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItType, true, copiedNodesList));
|
||||
copy->ItVar = static_cast<ZCC_VarName*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItVar, true, copiedNodesList));
|
||||
copy->LoopStatement = static_cast<ZCC_Statement*>(TreeNodeDeepCopy_Internal(ast, origCasted->LoopStatement, true, copiedNodesList));
|
||||
copy->ItExpr = static_cast<ZCC_Expression*>(TreeNodeDeepCopy_Internal(ast, origCasted->ItExpr, true, copiedNodesList));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_IfStmt:
|
||||
{
|
||||
TreeNodeDeepCopy_Start(IfStmt);
|
||||
|
|
|
|||
|
|
@ -145,6 +145,9 @@ enum EZCCTreeNodeType
|
|||
AST_MixinDef,
|
||||
AST_MixinStmt,
|
||||
AST_ArrayIterationStmt,
|
||||
AST_TwoArgIterationStmt,
|
||||
AST_ThreeArgIterationStmt,
|
||||
AST_TypedIterationStmt,
|
||||
|
||||
NUM_AST_NODE_TYPES
|
||||
};
|
||||
|
|
@ -532,6 +535,31 @@ struct ZCC_ArrayIterationStmt : ZCC_Statement
|
|||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_TwoArgIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItKey;
|
||||
ZCC_VarName* ItValue;
|
||||
ZCC_Expression* ItMap;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_ThreeArgIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItVar;
|
||||
ZCC_VarName* ItPos;
|
||||
ZCC_VarName* ItFlags;
|
||||
ZCC_Expression* ItBlock;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_TypedIterationStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_VarName* ItType;
|
||||
ZCC_VarName* ItVar;
|
||||
ZCC_Expression* ItExpr;
|
||||
ZCC_Statement* LoopStatement;
|
||||
};
|
||||
|
||||
struct ZCC_IfStmt : ZCC_Statement
|
||||
{
|
||||
ZCC_Expression *Condition;
|
||||
|
|
|
|||
|
|
@ -668,7 +668,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetBottomAlignOffset, GetBottomAlignOffset)
|
|||
ACTION_RETURN_FLOAT(GetBottomAlignOffset(self, code));
|
||||
}
|
||||
|
||||
static int StringWidth(FFont *font, const FString &str, bool localize)
|
||||
static int StringWidth(FFont *font, const FString &str, int localize)
|
||||
{
|
||||
const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
|
||||
return font->StringWidth(txt);
|
||||
|
|
@ -682,7 +682,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth)
|
|||
ACTION_RETURN_INT(StringWidth(self, str, localize));
|
||||
}
|
||||
|
||||
static int GetMaxAscender(FFont* font, const FString& str, bool localize)
|
||||
static int GetMaxAscender(FFont* font, const FString& str, int localize)
|
||||
{
|
||||
const char* txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
|
||||
return font->GetMaxAscender(txt);
|
||||
|
|
@ -696,7 +696,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender)
|
|||
ACTION_RETURN_INT(GetMaxAscender(self, str, localize));
|
||||
}
|
||||
|
||||
static int CanPrint(FFont *font, const FString &str, bool localize)
|
||||
static int CanPrint(FFont *font, const FString &str, int localize)
|
||||
{
|
||||
const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars();
|
||||
return font->CanPrint(txt);
|
||||
|
|
@ -1372,3 +1372,38 @@ DEFINE_ACTION_FUNCTION_NATIVE(DObject, FindFunction, FindFunctionPointer)
|
|||
ACTION_RETURN_POINTER(FindFunctionPointer(cls, fn.GetIndex()));
|
||||
}
|
||||
|
||||
FTranslationID R_FindCustomTranslation(FName name);
|
||||
|
||||
static int ZFindTranslation(int intname)
|
||||
{
|
||||
return R_FindCustomTranslation(ENamedName(intname)).index();
|
||||
}
|
||||
|
||||
static int MakeTransID(int g, int s)
|
||||
{
|
||||
return TRANSLATION(g, s).index();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Translation, GetID, ZFindTranslation)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(t);
|
||||
ACTION_RETURN_INT(ZFindTranslation(t));
|
||||
}
|
||||
|
||||
// same as above for the compiler which needs a class to look this up.
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinFindTranslation, ZFindTranslation)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(t);
|
||||
ACTION_RETURN_INT(ZFindTranslation(t));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Translation, MakeID, MakeTransID)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(g);
|
||||
PARAM_INT(t);
|
||||
ACTION_RETURN_INT(MakeTransID(g, t));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,14 @@ CUSTOM_CVAR(Bool, vm_jit, true, CVAR_NOINITCALL)
|
|||
Printf("You must restart " GAMENAME " for this change to take effect.\n");
|
||||
Printf("This cvar is currently not saved. You must specify it on the command line.");
|
||||
}
|
||||
CUSTOM_CVAR(Bool, vm_jit_aot, true, CVAR_NOINITCALL)
|
||||
{
|
||||
Printf("You must restart " GAMENAME " for this change to take effect.\n");
|
||||
Printf("This cvar is currently not saved. You must specify it on the command line.");
|
||||
}
|
||||
#else
|
||||
CVAR(Bool, vm_jit, false, CVAR_NOINITCALL|CVAR_NOSET)
|
||||
CVAR(Bool, vm_jit_aot, false, CVAR_NOINITCALL|CVAR_NOSET)
|
||||
FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames) { return FString(); }
|
||||
void JitRelease() {}
|
||||
#endif
|
||||
|
|
@ -282,6 +288,25 @@ static bool CanJit(VMScriptFunction *func)
|
|||
return false;
|
||||
}
|
||||
|
||||
void VMScriptFunction::JitCompile()
|
||||
{
|
||||
if(!(VarFlags & VARF_Abstract))
|
||||
{
|
||||
#ifdef HAVE_VM_JIT
|
||||
if (vm_jit && CanJit(this))
|
||||
{
|
||||
ScriptCall = ::JitCompile(this);
|
||||
if (!ScriptCall)
|
||||
ScriptCall = VMExec;
|
||||
}
|
||||
else
|
||||
#endif // HAVE_VM_JIT
|
||||
{
|
||||
ScriptCall = VMExec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret)
|
||||
{
|
||||
// [Player701] Check that we aren't trying to call an abstract function.
|
||||
|
|
@ -291,18 +316,8 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num
|
|||
{
|
||||
ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName);
|
||||
}
|
||||
#ifdef HAVE_VM_JIT
|
||||
if (vm_jit && CanJit(static_cast<VMScriptFunction*>(func)))
|
||||
{
|
||||
func->ScriptCall = JitCompile(static_cast<VMScriptFunction*>(func));
|
||||
if (!func->ScriptCall)
|
||||
func->ScriptCall = VMExec;
|
||||
}
|
||||
else
|
||||
#endif // HAVE_VM_JIT
|
||||
{
|
||||
func->ScriptCall = VMExec;
|
||||
}
|
||||
|
||||
static_cast<VMScriptFunction*>(func)->JitCompile();
|
||||
|
||||
return func->ScriptCall(func, params, numparams, ret, numret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,4 +481,6 @@ public:
|
|||
|
||||
private:
|
||||
static int FirstScriptCall(VMFunction *func, VMValue *params, int numparams, VMReturn *ret, int numret);
|
||||
void JitCompile();
|
||||
friend class FFunctionBuildList;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue