diff --git a/autogen/src/enum/codegen.cpp b/autogen/src/enum/codegen.cpp index 97e897b..3a23919 100644 --- a/autogen/src/enum/codegen.cpp +++ b/autogen/src/enum/codegen.cpp @@ -1,9 +1,7 @@ #include "codegen.h" #include "analysis.h" #include -#include #include -#include #include using namespace enum_; @@ -17,7 +15,7 @@ void enum_::writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAn out << " { " << entry.value << ", \"" << entry.name << "\" },\n"; } - out << "};"; + out << "};\n\n"; out << "static _EnumData __data_" << state.name << " = {\n" << " \"" << state.name << "\",\n" @@ -26,6 +24,8 @@ void enum_::writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAn << "};\n\n"; out << "namespace EnumType {\n" - << " const Enum " << state.name << "(&__data_" << state.name << ");\n" + // extern is necessary here too to prevent "const" from marking Enum as implicitly static + // https://stackoverflow.com/questions/2190919/mixing-extern-and-const#comment2509591_2190981 + << " extern const Enum " << state.name << "(&__data_" << state.name << ");\n" << "}\n\n"; } \ No newline at end of file diff --git a/autogen/src/object/analysis.cpp b/autogen/src/object/analysis.cpp index a4e7909..a93fbe6 100644 --- a/autogen/src/object/analysis.cpp +++ b/autogen/src/object/analysis.cpp @@ -80,7 +80,13 @@ static void processField(CXCursor cur, ClassAnalysis* state) { anly.flags = anly.flags | PropertyFlags::PropertyFlag_Readonly; CXType type = clang_getCursorType(cur); - anly.backingFieldType = x_clang_toString(clang_getTypeSpelling(type)).c_str(); + anly.backingFieldType = x_clang_toString(clang_getTypeSpelling(type)); + CXCursor typeCur = clang_getTypeDeclaration(type); + bool isEnum = findAnnotation(typeCur, "OB::def_enum").has_value(); + if (isEnum) { + anly.backingFieldType = "EnumItem"; + anly.backingFieldEnum = x_clang_toString(clang_getTypeSpelling(type)); + } state->properties.push_back(anly); diff --git a/autogen/src/object/analysis.h b/autogen/src/object/analysis.h index c486dc6..fd99498 100644 --- a/autogen/src/object/analysis.h +++ b/autogen/src/object/analysis.h @@ -31,6 +31,7 @@ struct PropertyAnalysis { std::string fieldName; CFrameMember cframeMember = CFrameMember_None; // for cframe_position_prop etc. std::string backingFieldType; + std::string backingFieldEnum; std::string onUpdateCallback; std::string category; PropertyFlags flags = (PropertyFlags)0; diff --git a/autogen/src/object/codegen.cpp b/autogen/src/object/codegen.cpp index 333b31d..9ea7fc4 100644 --- a/autogen/src/object/codegen.cpp +++ b/autogen/src/object/codegen.cpp @@ -89,6 +89,8 @@ static void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) { } else if (!subtype.empty()) { out << "\n std::weak_ptr ref = value.get();" << "\n this->" << prop.fieldName << " = ref.expired() ? std::weak_ptr<" << subtype << ">() : std::dynamic_pointer_cast<" << subtype << ">(ref.lock());"; + } else if (prop.backingFieldType == "EnumItem") { + out << "\n this->" << prop.fieldName << " = (" << prop.backingFieldEnum << ")value.get().Value();"; } else { out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";"; } @@ -143,6 +145,8 @@ static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) { out << "\n return Variant(" << prop.fieldName << ".Position());"; } else if (prop.cframeMember == CFrameMember_Rotation) { out << "\n return Variant(" << prop.fieldName << ".ToEulerAnglesXYZ());"; + } else if (prop.backingFieldType == "EnumItem") { + out << "\n return Variant(EnumType::" << prop.backingFieldEnum << ".FromValueInternal(" << prop.fieldName << "));"; } else { out << "\n return Variant(" << castToVariant(prop.fieldName, prop.backingFieldType) << ");"; } @@ -193,7 +197,7 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) { std::string typeInfo = TYPEINFO_REFS[prop.backingFieldType]; if (typeInfo.empty()) typeInfo = prop.backingFieldType + "::TYPE"; if (!parseWeakPtr(prop.backingFieldType).empty()) typeInfo = "InstanceRef::TYPE"; - if (prop.backingFieldType == "SurfaceType") typeInfo = "INT_TYPE"; + if (prop.backingFieldType == "EnumItem") typeInfo = "EnumType::" + prop.backingFieldEnum; std::string strFlags; if (prop.flags & PropertyFlag_Readonly) @@ -256,8 +260,8 @@ void object::writeCodeForClass(std::ofstream& out, std::string headerPath, Class out << "#define __AUTOGEN_EXTRA_INCLUDES__\n"; out << "#include \"" << state.headerPath << "\"\n\n"; - out << "#include \"datatypes/variant.h\"\n\n"; - out << "#include \"datatypes/primitives.h\"\n\n"; + out << "#include \"datatypes/variant.h\"\n"; + out << "#include \"datatypes/primitives.h\"\n"; out << "const InstanceType " << state.name << "::TYPE = {\n" << " .super = &" << state.baseClass << "::TYPE,\n" << " .className = \"" << state.name << "\",\n" diff --git a/core/src/datatypes/base.h b/core/src/datatypes/base.h index b61999a..0e61b41 100644 --- a/core/src/datatypes/base.h +++ b/core/src/datatypes/base.h @@ -38,11 +38,11 @@ struct InstanceType; struct TypeMeta { const TypeDesc* descriptor; union { - Enum* enum_; // Applicable for EnumItem - InstanceType* instType; // Applicable for InstanceRef + const Enum* enum_; // Applicable for EnumItem + const InstanceType* instType; // Applicable for InstanceRef }; inline TypeMeta(const TypeDesc* descriptor) : descriptor(descriptor) {} - TypeMeta(Enum*); - TypeMeta(InstanceType*); + TypeMeta(const Enum*); + TypeMeta(const InstanceType*); }; \ No newline at end of file diff --git a/core/src/datatypes/enum.cpp b/core/src/datatypes/enum.cpp index bf74c3f..062fd94 100644 --- a/core/src/datatypes/enum.cpp +++ b/core/src/datatypes/enum.cpp @@ -4,7 +4,7 @@ #include "error/data.h" #include -TypeMeta::TypeMeta(Enum* enum_) : enum_(enum_), descriptor(&EnumItem::TYPE) {} +TypeMeta::TypeMeta(const Enum* enum_) : enum_(enum_), descriptor(&EnumItem::TYPE) {} Enum::Enum(_EnumData* data) : data(data) {} @@ -34,6 +34,12 @@ std::optional Enum::FromValue(int value) const { return {}; } +EnumItem Enum::FromValueInternal(int value) const { + auto result = this->FromValue(value); + if (!result) return EnumItem(data, "", value); + return result.value(); +} + EnumItem::EnumItem(_EnumData* parentData, std::string name, int value) : parentData(parentData), name(name), value(value) {} // diff --git a/core/src/datatypes/enum.h b/core/src/datatypes/enum.h index 0cbc8e4..20cad8a 100644 --- a/core/src/datatypes/enum.h +++ b/core/src/datatypes/enum.h @@ -27,6 +27,8 @@ public: std::vector GetEnumItems() const; std::optional FromName(std::string) const; std::optional FromValue(int) const; + + EnumItem FromValueInternal(int) const; std::string ToString() const; void PushLuaValue(lua_State*) const; diff --git a/core/src/datatypes/ref.cpp b/core/src/datatypes/ref.cpp index 8173e03..f6b1aeb 100644 --- a/core/src/datatypes/ref.cpp +++ b/core/src/datatypes/ref.cpp @@ -10,7 +10,7 @@ #include "objects/base/member.h" #include -TypeMeta::TypeMeta(InstanceType* instType) : instType(instType), descriptor(&InstanceRef::TYPE) {} +TypeMeta::TypeMeta(const InstanceType* instType) : instType(instType), descriptor(&InstanceRef::TYPE) {} InstanceRef::InstanceRef() {}; InstanceRef::InstanceRef(std::weak_ptr instance) : ref(instance) {}; diff --git a/core/src/enum/meta.h b/core/src/enum/meta.h new file mode 100644 index 0000000..895f135 --- /dev/null +++ b/core/src/enum/meta.h @@ -0,0 +1,3 @@ +#pragma once + +#include "surface.h" \ No newline at end of file