BsScriptScriptCode.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #include "BsScriptScriptCode.h"
  2. #include "BsScriptResourceManager.h"
  3. #include "BsScriptMeta.h"
  4. #include "BsMonoField.h"
  5. #include "BsMonoClass.h"
  6. #include "BsMonoManager.h"
  7. #include "BsMonoUtil.h"
  8. #include "BsScriptAssemblyManager.h"
  9. #include "BsManagedSerializableObjectInfo.h"
  10. #include <regex>
  11. using namespace std::placeholders;
  12. namespace BansheeEngine
  13. {
  14. ScriptScriptCode::ScriptScriptCode(MonoObject* instance, const HScriptCode& scriptCode)
  15. :TScriptResource(instance, scriptCode)
  16. {
  17. }
  18. void ScriptScriptCode::initRuntimeData()
  19. {
  20. metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptScriptCode::internal_createInstance);
  21. metaData.scriptClass->addInternalCall("Internal_GetText", &ScriptScriptCode::internal_getText);
  22. metaData.scriptClass->addInternalCall("Internal_SetText", &ScriptScriptCode::internal_setText);
  23. metaData.scriptClass->addInternalCall("Internal_IsEditorScript", &ScriptScriptCode::internal_isEditorScript);
  24. metaData.scriptClass->addInternalCall("Internal_SetEditorScript", &ScriptScriptCode::internal_setEditorScript);
  25. metaData.scriptClass->addInternalCall("Internal_GetTypes", &ScriptScriptCode::internal_getTypes);
  26. }
  27. void ScriptScriptCode::internal_createInstance(MonoObject* instance, MonoString* text)
  28. {
  29. WString strText = MonoUtil::monoToWString(text);
  30. HScriptCode scriptCode = ScriptCode::create(strText);
  31. ScriptScriptCode* scriptInstance;
  32. ScriptResourceManager::instance().createScriptResource(instance, scriptCode, &scriptInstance);
  33. }
  34. MonoString* ScriptScriptCode::internal_getText(ScriptScriptCode* thisPtr)
  35. {
  36. HScriptCode scriptCode = thisPtr->getHandle();
  37. if (!scriptCode.isLoaded())
  38. MonoUtil::wstringToMono(MonoManager::instance().getDomain(), L"");
  39. return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), scriptCode->getString());
  40. }
  41. void ScriptScriptCode::internal_setText(ScriptScriptCode* thisPtr, MonoString* text)
  42. {
  43. HScriptCode scriptCode = thisPtr->getHandle();
  44. if (!scriptCode.isLoaded())
  45. return;
  46. scriptCode->setString(MonoUtil::monoToWString(text));
  47. }
  48. bool ScriptScriptCode::internal_isEditorScript(ScriptScriptCode* thisPtr)
  49. {
  50. HScriptCode scriptCode = thisPtr->getHandle();
  51. if (!scriptCode.isLoaded())
  52. return false;
  53. return scriptCode->getIsEditorScript();
  54. }
  55. void ScriptScriptCode::internal_setEditorScript(ScriptScriptCode* thisPtr, bool value)
  56. {
  57. HScriptCode scriptCode = thisPtr->getHandle();
  58. if (!scriptCode.isLoaded())
  59. return;
  60. scriptCode->setIsEditorScript(value);
  61. }
  62. MonoArray* ScriptScriptCode::internal_getTypes(ScriptScriptCode* thisPtr)
  63. {
  64. HScriptCode scriptCode = thisPtr->getHandle();
  65. Vector<FullTypeName> types;
  66. if (scriptCode.isLoaded())
  67. types = parseTypes(scriptCode->getString());
  68. Vector<MonoReflectionType*> validTypes;
  69. for (auto& type : types)
  70. {
  71. ManagedSerializableObjectInfoPtr objInfo;
  72. if (ScriptAssemblyManager::instance().getSerializableObjectInfo(toString(type.first), toString(type.second), objInfo))
  73. {
  74. MonoType* monoType = mono_class_get_type(objInfo->mTypeInfo->getMonoClass());
  75. validTypes.push_back(mono_type_get_object(MonoManager::instance().getDomain(), monoType));
  76. }
  77. }
  78. UINT32 numValidTypes = (UINT32)validTypes.size();
  79. MonoClass* typeClass = ScriptAssemblyManager::instance().getSystemTypeClass();
  80. MonoArray* output = mono_array_new(MonoManager::instance().getDomain(), typeClass->_getInternalClass(), numValidTypes);
  81. for (UINT32 i = 0; i < numValidTypes; i++)
  82. mono_array_set(output, MonoReflectionType*, i, validTypes[i]);
  83. return output;
  84. }
  85. MonoObject* ScriptScriptCode::createInstance()
  86. {
  87. return metaData.scriptClass->createInstance();
  88. }
  89. Vector<ScriptScriptCode::FullTypeName> ScriptScriptCode::parseTypes(const WString& code)
  90. {
  91. struct NamespaceData
  92. {
  93. WString ns;
  94. INT32 bracketIdx;
  95. };
  96. Vector<FullTypeName> output;
  97. Stack<NamespaceData> namespaces;
  98. // TODO: Won't match non latin characters because C++ regex doesn't support unicode character classes
  99. // and writing out Unicode ranges for all the characters C# supports as identifiers is too tedious at the moment.
  100. // Classes that need to match: \p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}
  101. WString identifierPattern = LR"([_@a-zA-Z][_\da-zA-Z]*)";
  102. std::wregex identifierRegex(identifierPattern);
  103. WString nsToken = L"namespace";
  104. WString classToken = L"class";
  105. UINT32 idx = 0;
  106. INT32 bracketIdx = 0;
  107. for (auto iter = code.begin(); iter != code.end(); ++iter)
  108. {
  109. wchar_t ch = *iter;
  110. if (code.compare(idx, classToken.size(), classToken) == 0)
  111. {
  112. std::wsmatch results;
  113. if (std::regex_search(iter + classToken.size(), code.end(), results, identifierRegex))
  114. {
  115. WString ns = L"";
  116. if (!namespaces.empty())
  117. ns = namespaces.top().ns;
  118. std::wstring tempStr = results[0];
  119. WString typeName = tempStr.c_str();
  120. output.push_back(FullTypeName());
  121. FullTypeName& nsTypePair = output.back();
  122. nsTypePair.first = ns;
  123. nsTypePair.second = typeName;
  124. }
  125. }
  126. else if (code.compare(idx, nsToken.size(), nsToken) == 0)
  127. {
  128. std::wsmatch results;
  129. if (std::regex_search(iter + nsToken.size(), code.end(), results, identifierRegex))
  130. {
  131. std::wstring tempStr = results[0];
  132. WString ns = tempStr.c_str();
  133. namespaces.push({ ns, bracketIdx + 1 });
  134. }
  135. }
  136. else if (ch == '{')
  137. {
  138. bracketIdx++;
  139. }
  140. else if (ch == '}')
  141. {
  142. bracketIdx--;
  143. }
  144. idx++;
  145. }
  146. return output;
  147. }
  148. }