From 53334bb18140e4e6f79fbcfb10ffe138459b88f3 Mon Sep 17 00:00:00 2001 From: ZXShady <153229951+ZXShady@users.noreply.github.com> Date: Tue, 17 Mar 2026 19:49:47 +0200 Subject: [PATCH 1/2] Add the enum flag type this implements the flag enum type that ensures ~, |, &, ^ return the same type. --- sdk/angelscript/include/angelscript.h | 3 +- sdk/angelscript/source/as_builder.cpp | 32 ++++++-- sdk/angelscript/source/as_compiler.cpp | 95 ++++++++++++++++++++-- sdk/angelscript/source/as_datatype.cpp | 8 +- sdk/angelscript/source/as_datatype.h | 4 +- sdk/angelscript/source/as_parser.cpp | 16 ++-- sdk/angelscript/source/as_restore.cpp | 23 +++++- sdk/angelscript/source/as_scriptengine.cpp | 4 +- sdk/angelscript/source/as_scriptengine.h | 2 +- sdk/angelscript/source/as_tokendef.h | 1 + sdk/angelscript/source/as_typeinfo.cpp | 10 +++ sdk/angelscript/source/as_typeinfo.h | 6 +- 12 files changed, 170 insertions(+), 34 deletions(-) diff --git a/sdk/angelscript/include/angelscript.h b/sdk/angelscript/include/angelscript.h index cf5188e38..ce0a291c2 100644 --- a/sdk/angelscript/include/angelscript.h +++ b/sdk/angelscript/include/angelscript.h @@ -723,7 +723,7 @@ class asIScriptEngine virtual int GetDefaultArrayTypeId() const = 0; // Enums - virtual int RegisterEnum(const char* typeName, const char* underlyingType = "int32") = 0; + virtual int RegisterEnum(const char* typeName, const char* underlyingType = "int32", bool isFlags = false) = 0; virtual int RegisterEnumValue(const char* type, const char* name, asINT64 value) = 0; virtual asUINT GetEnumCount() const = 0; virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; @@ -1127,6 +1127,7 @@ class asITypeInfo // Enums virtual asUINT GetEnumValueCount() const = 0; virtual const char *GetEnumValueByIndex(asUINT index, asINT64 *outValue) const = 0; + virtual bool IsFlagEnum() const = 0; #ifdef AS_DEPRECATED // deprecated since 2025-09-13, 2.39.0 diff --git a/sdk/angelscript/source/as_builder.cpp b/sdk/angelscript/source/as_builder.cpp index b9a43030b..26f4528e3 100644 --- a/sdk/angelscript/source/as_builder.cpp +++ b/sdk/angelscript/source/as_builder.cpp @@ -2771,6 +2771,7 @@ void asCBuilder::CompileGlobalVariables() if( gvar->isEnumValue ) { + asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); int r; if( gvar->initializationNode ) { @@ -2780,8 +2781,6 @@ void asCBuilder::CompileGlobalVariables() // Set the namespace that should be used during the compilation func.nameSpace = gvar->datatype.GetTypeInfo()->nameSpace; - // Temporarily switch the type of the variable to the enums' underlying type so it can be compiled properly - asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); asCDataType saveType; saveType = gvar->datatype; gvar->datatype = enumType->enumType; @@ -2794,7 +2793,6 @@ void asCBuilder::CompileGlobalVariables() else { r = 0; - // When there is no assignment the value is the last + 1 asINT64 enumVal = 0; asCSymbolTable::iterator prev_it = it; @@ -2804,7 +2802,28 @@ void asCBuilder::CompileGlobalVariables() sGlobalVariableDescription *gvar2 = *prev_it; if(gvar2->datatype == gvar->datatype ) { - enumVal = asINT64(gvar2->constantValue) + 1; + const asINT64 prevVal = gvar2->constantValue; + + if( enumType->isFlags) + { + if ( prevVal <= 0 ) + enumVal = 1; + else + { + enumVal = prevVal; + enumVal |= enumVal >> 1; + enumVal |= enumVal >> 2; + enumVal |= enumVal >> 4; + enumVal |= enumVal >> 8; + enumVal |= enumVal >> 16; + enumVal |= enumVal >> 32; + enumVal++; + } + } + else + { + enumVal = prevVal + 1; + } if( !gvar2->isCompiled ) { @@ -4679,6 +4698,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp // Is it a shared enum? bool isShared = false; bool isExternal = false; + bool isFlags = false; asCEnumType *existingSharedType = 0; asCScriptNode *tmp = node->firstChild; while( tmp->nodeType == snIdentifier ) @@ -4687,6 +4707,8 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp isShared = true; else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN)) isExternal = true; + else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, FLAG_TOKEN)) + isFlags = true; else break; tmp = tmp->next; @@ -4753,7 +4775,7 @@ int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSp } else { - st = asNEW(asCEnumType)(engine); + st = asNEW(asCEnumType)(engine,isFlags); if( st == 0 ) return asOUT_OF_MEMORY; diff --git a/sdk/angelscript/source/as_compiler.cpp b/sdk/angelscript/source/as_compiler.cpp index dd4299a50..442ff2c9c 100644 --- a/sdk/angelscript/source/as_compiler.cpp +++ b/sdk/angelscript/source/as_compiler.cpp @@ -4916,7 +4916,14 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB // else, allow value types to be converted to bool using 'bool opImplConv()' else if (expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE)) ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); - + if(expr.type.dataType.IsEnumType()) + { + const asCEnumType *et = CastToEnumType(expr.type.dataType.GetTypeInfo()); + if (et->isFlags) + { + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); + } + } if (!expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true))) { asCString str; @@ -7375,9 +7382,21 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asUINT cost = asCC_NO_CONV; if (to.IsBooleanType() || ctx->type.dataType.IsBooleanType()) { - // conversions to/from bool are not allowed. A ternary (expr?1:0) should be used instead - // If at any time support for this is added, then remember that booleans can be different size on different platforms - return asCC_NO_CONV; + // allow flagenums to be implicitly converted to bool. + if (to.IsBooleanType() && ctx->type.dataType.IsEnumType()) + { + asCEnumType *et = CastToEnumType(ctx->type.dataType.GetTypeInfo()); + if (et->isFlags) + cost = asCC_ENUM_DIFF_SIZE_CONV; + else + return asCC_NO_CONV; + } + else + { + // conversions to/from bool are not allowed. A ternary (expr?1:0) should be used instead + // If at any time support for this is added, then remember that booleans can be different size on different platforms + return asCC_NO_CONV; + } } else if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) cost = asCC_FLOAT_TO_INT_CONV; @@ -7409,6 +7428,20 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const { // When generating the code the decision has already been made, so we don't bother determining the cost + if (to.IsBooleanType() && ctx->type.dataType.IsEnumType()) + { + if (ctx->type.isConstant) + ctx->type.SetConstantB(to, ctx->type.GetConstantQW() != 0); + else + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_iTOb, (short)ctx->type.stackOffset); + + ctx->type.dataType = to; + } + return cost; // handled it already + } + // Convert smaller types to 32bit first int s = ctx->type.dataType.GetSizeInMemoryBytes(); if( s < 4 ) @@ -9217,9 +9250,30 @@ void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCData // References cannot be constants if( from->type.dataType.IsReference() ) return; - - if((to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) + + if(to.IsBooleanType() && from->type.dataType.IsEnumType() == 2) + { + if (from->type.dataType.IsUnsignedType() || from->type.dataType.IsIntegerType()) + { + asQWORD qw; + + if (from->type.dataType.GetSizeInMemoryBytes() == 1) + qw = from->type.GetConstantB(); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + qw = from->type.GetConstantW(); + else if (from->type.dataType.GetSizeInMemoryBytes() == 4) + qw = from->type.GetConstantDW(); + else + qw = from->type.GetConstantQW(); + + if (to.GetSizeInMemoryBytes() == 1) + from->type.SetConstantB(to, qw != 0); + } + } + else if((to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) { + + if( from->type.dataType.IsFloatType() || from->type.dataType.IsDoubleType() || from->type.dataType.IsUnsignedType() || @@ -13748,13 +13802,18 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx } else if( op == ttNot ) { + asCDataType originalType = ctx->type.dataType; + asCEnumType *et = CastToEnumType(originalType.GetTypeInfo()); + bool isFlag = (et && et->isFlags); + // If turned on, allow the compiler to use either 'bool opImplConv()' or 'bool opConv()' on the type if (engine->ep.boolConversionMode == 1) ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_EXPLICIT_VAL_CAST); // else, allow value types to be converted to bool using 'bool opImplConv()' else if (ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE)) ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); - + else if(isFlag) + ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) { if( ctx->type.isConstant ) @@ -13783,6 +13842,10 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx } else if( op == ttBitNot ) { + asCDataType originalType = ctx->type.dataType; + asCEnumType *et = CastToEnumType(originalType.GetTypeInfo()); + bool isFlag = (et && et->isFlags); + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) return -1; @@ -13820,6 +13883,9 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx ctx->type.SetConstantDW(~ctx->type.GetConstantDW()); else ctx->type.SetConstantQW(~ctx->type.GetConstantQW()); + + if(isFlag) + ctx->type.dataType = originalType; return 0; } @@ -13830,6 +13896,9 @@ int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx ctx->bc.InstrSHORT(asBC_BNOT, (short)ctx->type.stackOffset); else ctx->bc.InstrSHORT(asBC_BNOT64, (short)ctx->type.stackOffset); + + if(isFlag) + ctx->type.dataType = originalType; } else { @@ -15925,7 +15994,19 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCE op == ttBitShiftRight || op == ttShiftRightLAssign || op == ttBitShiftRightArith || op == ttShiftRightAAssign ) { + asCDataType originalEnumType; + bool isFlags = false; + if (lctx->type.dataType.IsEnumType() && + rctx->type.dataType.IsEnumType() && + lctx->type.dataType.GetTypeInfo() == rctx->type.dataType.GetTypeInfo()) + { + isFlags = CastToEnumType(lctx->type.dataType.GetTypeInfo())->isFlags; + originalEnumType = lctx->type.dataType; + } CompileBitwiseOperator(node, lctx, rctx, ctx, op); + if (isFlags) { + ctx->type.dataType = originalEnumType; + } return 0; } diff --git a/sdk/angelscript/source/as_datatype.cpp b/sdk/angelscript/source/as_datatype.cpp index 404d8fe8e..091ea26dc 100644 --- a/sdk/angelscript/source/as_datatype.cpp +++ b/sdk/angelscript/source/as_datatype.cpp @@ -741,15 +741,17 @@ asSTypeBehaviour *asCDataType::GetBehaviour() const return ot ? &ot->beh : 0; } -bool asCDataType::IsEnumType() const +unsigned int asCDataType::IsEnumType() const { // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) - return true; + { + return CastToEnumType(typeInfo)->isFlags ? 2 : 1; + } - return false; + return 0; } END_AS_NAMESPACE diff --git a/sdk/angelscript/source/as_datatype.h b/sdk/angelscript/source/as_datatype.h index 8ff058bdb..92f462697 100644 --- a/sdk/angelscript/source/as_datatype.h +++ b/sdk/angelscript/source/as_datatype.h @@ -56,7 +56,6 @@ struct asSNameSpace; // TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCExprValue // MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed - class asCDataType { public: @@ -100,7 +99,8 @@ class asCDataType bool IsHandleToAuto() const {return isAuto && isObjectHandle;} bool IsHandleToConst() const; bool IsArrayType() const; - bool IsEnumType() const; + // returns 2 if it is a flag enum otherwise return 1 + unsigned int IsEnumType() const; bool IsAnyType() const {return tokenType == ttQuestion;} bool IsHandleToAsHandleType() const {return isHandleToAsHandleType;} bool IsAbstractClass() const; diff --git a/sdk/angelscript/source/as_parser.cpp b/sdk/angelscript/source/as_parser.cpp index dc8e3a463..829c0b927 100644 --- a/sdk/angelscript/source/as_parser.cpp +++ b/sdk/angelscript/source/as_parser.cpp @@ -2602,12 +2602,13 @@ asCScriptNode *asCParser::ParseScript(bool inBlock) sToken tStart; GetToken(&tStart); - // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition + // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' , 'flag' so they don't have to be checked in every condition sToken t1 = tStart; while (IdentifierIs(t1, SHARED_TOKEN) || IdentifierIs(t1, EXTERNAL_TOKEN) || IdentifierIs(t1, FINAL_TOKEN) || - IdentifierIs(t1, ABSTRACT_TOKEN)) + IdentifierIs(t1, ABSTRACT_TOKEN) || + IdentifierIs(t1,FLAG_TOKEN)) GetToken(&t1); RewindTo(&tStart); @@ -2836,9 +2837,10 @@ asCScriptNode *asCParser::ParseEnumeration() // Optional 'shared' and 'external' token GetToken(&token); + while( IdentifierIs(token, SHARED_TOKEN) || - IdentifierIs(token, EXTERNAL_TOKEN) ) - { + IdentifierIs(token, EXTERNAL_TOKEN) || + IdentifierIs(token, FLAG_TOKEN)) { RewindTo(&token); node->AddChildLast(ParseIdentifier()); if( isSyntaxError ) return node; @@ -2951,13 +2953,9 @@ asCScriptNode *asCParser::ParseEnumeration() if( token.type == ttAssignment ) { - asCScriptNode *tmp; - RewindTo(&token); - tmp = SuperficiallyParseVarInit(); - - node->AddChildLast(tmp); + node->AddChildLast(SuperficiallyParseVarInit()); if( isSyntaxError ) return node; GetToken(&token); } diff --git a/sdk/angelscript/source/as_restore.cpp b/sdk/angelscript/source/as_restore.cpp index d5e55f4a7..fce67f658 100644 --- a/sdk/angelscript/source/as_restore.cpp +++ b/sdk/angelscript/source/as_restore.cpp @@ -157,7 +157,7 @@ int asCReader::ReadInner() module->m_enumTypes.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { - asCEnumType *et = asNEW(asCEnumType)(engine); + asCEnumType *et = asNEW(asCEnumType)(engine,false); if( et == 0 ) { error = true; @@ -1634,7 +1634,19 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern // TODO: weak: Should not do this if the class has been declared with 'noweak' engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); } - + asCEnumType *et = CastToEnumType(type); + if(et) + { + char c; + ReadData(&c,1); + if(c == 'f') + et->isFlags = true; + else if (c != ' ') + { + error = true; + return; + } + } // external shared flag if (type->flags & asOBJ_SHARED) { @@ -4567,6 +4579,13 @@ void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase) // namespace WriteString(&type->nameSpace->name); + if ((type->flags & asOBJ_ENUM)) + { + const asCEnumType* et = CastToEnumType(type); + asASSERT(et != nullptr); + const char c = et->isFlags ? 'f' : ' '; + WriteData(&c, 1); + } // external shared flag if ((type->flags & asOBJ_SHARED)) { diff --git a/sdk/angelscript/source/as_scriptengine.cpp b/sdk/angelscript/source/as_scriptengine.cpp index 5ce1e4493..d18761058 100644 --- a/sdk/angelscript/source/as_scriptengine.cpp +++ b/sdk/angelscript/source/as_scriptengine.cpp @@ -6258,7 +6258,7 @@ asITypeInfo *asCScriptEngine::GetTypedefByIndex(asUINT index) const } // interface -int asCScriptEngine::RegisterEnum(const char* typeName, const char* underlyingType) +int asCScriptEngine::RegisterEnum(const char* typeName, const char* underlyingType, bool isFlags) { // Check the name if( NULL == typeName ) @@ -6303,7 +6303,7 @@ int asCScriptEngine::RegisterEnum(const char* typeName, const char* underlyingTy if( r < 0 ) return ConfigError(asNAME_TAKEN, "RegisterEnum", typeName, 0); - asCEnumType *st = asNEW(asCEnumType)(this); + asCEnumType *st = asNEW(asCEnumType)(this, isFlags); if( st == 0 ) return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", typeName, 0); diff --git a/sdk/angelscript/source/as_scriptengine.h b/sdk/angelscript/source/as_scriptengine.h index 0cd50b1be..d0d019bee 100644 --- a/sdk/angelscript/source/as_scriptengine.h +++ b/sdk/angelscript/source/as_scriptengine.h @@ -123,7 +123,7 @@ class asCScriptEngine : public asIScriptEngine virtual int GetDefaultArrayTypeId() const; // Enums - virtual int RegisterEnum(const char* typeName, const char* underlyingType = "int32"); + virtual int RegisterEnum(const char* typeName, const char* underlyingType = "int32", bool isFlags = false); virtual int RegisterEnumValue(const char* type, const char* name, asINT64 value); virtual asUINT GetEnumCount() const; virtual asITypeInfo *GetEnumByIndex(asUINT index) const; diff --git a/sdk/angelscript/source/as_tokendef.h b/sdk/angelscript/source/as_tokendef.h index dfe1eb4a6..df5a4efeb 100644 --- a/sdk/angelscript/source/as_tokendef.h +++ b/sdk/angelscript/source/as_tokendef.h @@ -313,6 +313,7 @@ const char * const whiteSpace = " \t\r\n"; // These only have meaning in specific situations. Outside these // situations they are treated as normal identifiers. const char * const THIS_TOKEN = "this"; +const char * const FLAG_TOKEN = "flag"; const char * const FROM_TOKEN = "from"; const char * const SUPER_TOKEN = "super"; const char * const SHARED_TOKEN = "shared"; diff --git a/sdk/angelscript/source/as_typeinfo.cpp b/sdk/angelscript/source/as_typeinfo.cpp index 3b4b4ed06..e30c2ba42 100644 --- a/sdk/angelscript/source/as_typeinfo.cpp +++ b/sdk/angelscript/source/as_typeinfo.cpp @@ -134,6 +134,11 @@ asIScriptModule *asCTypeInfo::GetModule() const return module; } +bool asCTypeInfo::IsFlagEnum() const +{ + return false; +} + void *asCTypeInfo::SetUserData(void *data, asPWORD type) { // As a thread might add a new new user data at the same time as another @@ -376,6 +381,11 @@ const char *asCEnumType::GetEnumValueByIndex(asUINT index, asINT64 *outValue) co return enumValues[index]->name.AddressOf(); } +bool asCEnumType::IsFlagEnum() const +{ + return isFlags; +} + // interface int asCEnumType::GetUnderlyingTypeId() const { diff --git a/sdk/angelscript/source/as_typeinfo.h b/sdk/angelscript/source/as_typeinfo.h index d0fb36da7..4e35f4b31 100644 --- a/sdk/angelscript/source/as_typeinfo.h +++ b/sdk/angelscript/source/as_typeinfo.h @@ -121,7 +121,7 @@ class asCTypeInfo : public asITypeInfo // Enums asUINT GetEnumValueCount() const { return 0; } const char *GetEnumValueByIndex(asUINT index, asINT64 *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; } - + bool IsFlagEnum() const; #ifdef AS_DEPRECATED // deprecated since 2025-09-13, 2.39.0 // Typedef @@ -198,14 +198,16 @@ struct asSEnumValue class asCEnumType : public asCTypeInfo { public: - asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + asCEnumType(asCScriptEngine *engine,bool isFlags) : asCTypeInfo(engine),isFlags(isFlags) {} ~asCEnumType(); asCArray enumValues; asCDataType enumType; + bool isFlags; asUINT GetEnumValueCount() const; const char *GetEnumValueByIndex(asUINT index, asINT64 *outValue) const; + bool IsFlagEnum() const; int GetUnderlyingTypeId() const; From 120cd626a349cd022d3cd002d9adbd3ea862961a Mon Sep 17 00:00:00 2001 From: ZXShady <153229951+ZXShady@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:39:22 +0200 Subject: [PATCH 2/2] add flag enum tesgts --- sdk/tests/test_feature/source/test_enum.cpp | 111 ++++++++++++++++++ .../test_feature/source/test_saveload.cpp | 6 +- sdk/tests/test_feature/source/test_shared.cpp | 4 +- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/sdk/tests/test_feature/source/test_enum.cpp b/sdk/tests/test_feature/source/test_enum.cpp index d4b16157f..5d6e8ba32 100644 --- a/sdk/tests/test_feature/source/test_enum.cpp +++ b/sdk/tests/test_feature/source/test_enum.cpp @@ -879,6 +879,117 @@ static bool TestEnum() engine->Release(); } + + { + engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); + bout.buffer = ""; + engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); + + asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE); + + mod->AddScriptSection("test", + "flag enum MyFlags { \n" + " none, \n" + " a, \n" + " b, \n" + " c, \n" + " all = a | b | c, \n" + " next = 24, \n" + " next32, \n" + "} \n" + "void main() { \n" + " assert( none == 0 ); \n" + " assert( a == 1 ); \n" + " assert( b == 2 ); \n" + " assert( c == 4 ); \n" + " assert( next == 24 ); \n" + " assert( next32 == 32 ); \n" + " assert( all == 7 ); \n" + " MyFlags state = a | c; \n" + " assert( state == 5 ); \n" + " if(state & a) {} else {assert(false);}\n" + " if(state & b) {assert(false);} else {}\n" + " if(!(state & c)) { assert(false);} \n" + " state &= ~c; \n" + " if(state & c) {assert(false);} \n" + " state |= c; \n" + " if(state & c) {} else {assert(false);}\n" + "} \n"); + + engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); + + r = mod->Build(); + if( r < 0 ) + { + PRINTF("flag enum failed to build.\n"); + TEST_FAILED; + } + + r = ExecuteString(engine, "main()", mod); + if( r != asEXECUTION_FINISHED ) + { + PRINTF("flag enum logic incorrect at runtime.\n"); + TEST_FAILED; + } + + engine->ShutDownAndRelease(); + } + + { + engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); + bout.buffer = ""; + engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); + + engine->RegisterEnum("MyFlags","uint32",true); + engine->RegisterEnumValue("MyFlags","none",0); + engine->RegisterEnumValue("MyFlags","a",1 << 0); + engine->RegisterEnumValue("MyFlags","b",1 << 1); + engine->RegisterEnumValue("MyFlags","c",1 << 2); + engine->RegisterEnumValue("MyFlags","all",1 | 2 | 4); + + asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE); + + + mod->AddScriptSection("test", + "void main() { \n" + " assert( none == 0 ); \n" + " assert( a == 1 ); \n" + " assert( b == 2 ); \n" + " assert( c == 4 ); \n" + " assert( all == 7 ); \n" + " MyFlags state = a | c; \n" + " assert( state == 5 ); \n" + " if(state & a) {} else {assert(false);}\n" + " if(state & b) {assert(false);} else {}\n" + " if(!(state & c)) { assert(false);} \n" + " state &= ~c; \n" + " if(state & c) {assert(false);} \n" + " state |= c; \n" + " if(state & c) {} else {assert(false);}\n" + "} \n"); + + engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); + + r = mod->Build(); + if( r < 0 ) + { + PRINTF("flag enum failed to build. %s\n",bout.buffer.c_str()); + TEST_FAILED; + } + + r = ExecuteString(engine, "main()", mod); + if( r != asEXECUTION_FINISHED ) + { + + PRINTF("flag enum logic incorrect at runtime.\n"); + TEST_FAILED; + } + + engine->ShutDownAndRelease(); + } + + + // Success return fail; } diff --git a/sdk/tests/test_feature/source/test_saveload.cpp b/sdk/tests/test_feature/source/test_saveload.cpp index 7e638fc1d..fc9cf8afc 100644 --- a/sdk/tests/test_feature/source/test_saveload.cpp +++ b/sdk/tests/test_feature/source/test_saveload.cpp @@ -2526,7 +2526,7 @@ bool Test() mod->SaveByteCode(&stream2, true); #ifndef STREAM_TO_FILE - if (stream.buffer.size() != 2469) + if (stream.buffer.size() != 2470) PRINTF("The saved byte code is not of the expected size. It is %d bytes\n", (int)stream.buffer.size()); asUINT zeroes = stream.CountZeroes(); if (zeroes != 651) @@ -2535,14 +2535,14 @@ bool Test() // Mac OS X PPC has more zeroes, probably due to the bool type being 4 bytes } asDWORD crc32 = ComputeCRC32(&stream.buffer[0], asUINT(stream.buffer.size())); - if( crc32 != 0x7E58AAF1) + if( crc32 != 0x9F8CDF45) { PRINTF("The saved byte code has different checksum than the expected. Got 0x%X\n", crc32); TEST_FAILED; } // Without debug info - if (stream2.buffer.size() != 2058) + if (stream2.buffer.size() != 2059) PRINTF("The saved byte code without debug info is not of the expected size. It is %d bytes\n", (int)stream2.buffer.size()); zeroes = stream2.CountZeroes(); if (zeroes != 479) diff --git a/sdk/tests/test_feature/source/test_shared.cpp b/sdk/tests/test_feature/source/test_shared.cpp index 5d403c8bb..082fde8ee 100644 --- a/sdk/tests/test_feature/source/test_shared.cpp +++ b/sdk/tests/test_feature/source/test_shared.cpp @@ -729,14 +729,14 @@ const char* file2 = " \ TEST_FAILED; asDWORD crc32 = ComputeCRC32(&bc1.buffer[0], asUINT(bc1.buffer.size())); - if (crc32 != 0x59B3E29) + if (crc32 != 0x1E099D7D) { PRINTF("The saved byte code has different checksum than the expected. Got 0x%X\n", crc32); TEST_FAILED; } crc32 = ComputeCRC32(&bc2.buffer[0], asUINT(bc2.buffer.size())); - if (crc32 != 0x504D4243) + if (crc32 != 0x44D3EABC) { PRINTF("The saved byte code has different checksum than the expected. Got 0x%X\n", crc32); TEST_FAILED;