PageRenderTime 72ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/xbmc/visualizations/Vortex/angelscript/angelscript/source/as_scriptengine.cpp

http://github.com/xbmc/xbmc
C++ | 4005 lines | 2955 code | 632 blank | 418 comment | 874 complexity | 865bdcb2382977594909b1cc468f8b12 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-2.0, 0BSD, Unlicense, GPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2009 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_scriptengine.cpp
  25. //
  26. // The implementation of the script engine interface
  27. //
  28. #include <stdlib.h>
  29. #include "as_config.h"
  30. #include "as_scriptengine.h"
  31. #include "as_builder.h"
  32. #include "as_context.h"
  33. #include "as_string_util.h"
  34. #include "as_tokenizer.h"
  35. #include "as_texts.h"
  36. #include "as_module.h"
  37. #include "as_callfunc.h"
  38. #include "as_arrayobject.h"
  39. #include "as_generic.h"
  40. #include "as_scriptobject.h"
  41. #include "as_compiler.h"
  42. BEGIN_AS_NAMESPACE
  43. extern "C"
  44. {
  45. AS_API const char * asGetLibraryVersion()
  46. {
  47. #ifdef _DEBUG
  48. return ANGELSCRIPT_VERSION_STRING " DEBUG";
  49. #else
  50. return ANGELSCRIPT_VERSION_STRING;
  51. #endif
  52. }
  53. AS_API const char * asGetLibraryOptions()
  54. {
  55. const char *string = " "
  56. // Options
  57. #ifdef AS_MAX_PORTABILITY
  58. "AS_MAX_PORTABILITY "
  59. #endif
  60. #ifdef AS_DEBUG
  61. "AS_DEBUG "
  62. #endif
  63. #ifdef AS_NO_CLASS_METHODS
  64. "AS_NO_CLASS_METHODS "
  65. #endif
  66. #ifdef AS_USE_DOUBLE_AS_FLOAT
  67. "AS_USE_DOUBLE_AS_FLOAT "
  68. #endif
  69. #ifdef AS_64BIT_PTR
  70. "AS_64BIT_PTR "
  71. #endif
  72. #ifdef AS_NO_THREADS
  73. "AS_NO_THREADS "
  74. #endif
  75. #ifdef AS_NO_ATOMIC
  76. "AS_NO_ATOMIC "
  77. #endif
  78. // Target system
  79. #ifdef AS_WIN
  80. "AS_WIN "
  81. #endif
  82. #ifdef AS_LINUX
  83. "AS_LINUX "
  84. #endif
  85. #ifdef AS_MAC
  86. "AS_MAC "
  87. #endif
  88. #ifdef AS_BSD
  89. "AS_BSD "
  90. #endif
  91. #ifdef AS_XBOX
  92. "AS_XBOX "
  93. #endif
  94. #ifdef AS_XBOX360
  95. "AS_XBOX360 "
  96. #endif
  97. #ifdef AS_PSP
  98. "AS_PSP "
  99. #endif
  100. #ifdef AS_PS2
  101. "AS_PS2 "
  102. #endif
  103. #ifdef AS_PS3
  104. "AS_PS3 "
  105. #endif
  106. #ifdef AS_DC
  107. "AS_DC "
  108. #endif
  109. #ifdef AS_GC
  110. "AS_GC "
  111. #endif
  112. #ifdef AS_WII
  113. "AS_WII "
  114. #endif
  115. #ifdef AS_IPHONE
  116. "AS_IPHONE "
  117. #endif
  118. #ifdef AS_ANDROID
  119. "AS_ANDROID "
  120. #endif
  121. // CPU family
  122. #ifdef AS_PPC
  123. "AS_PPC "
  124. #endif
  125. #ifdef AS_PPC_64
  126. "AS_PPC_64 "
  127. #endif
  128. #ifdef AS_X86
  129. "AS_X86 "
  130. #endif
  131. #ifdef AS_MIPS
  132. "AS_MIPS "
  133. #endif
  134. #ifdef AS_SH4
  135. "AS_SH4 "
  136. #endif
  137. #ifdef AS_XENON
  138. "AS_XENON "
  139. #endif
  140. #ifdef AS_ARM
  141. "AS_ARM "
  142. #endif
  143. ;
  144. return string;
  145. }
  146. AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version)
  147. {
  148. // Verify the version that the application expects
  149. if( (version/10000) != (ANGELSCRIPT_VERSION/10000) )
  150. return 0;
  151. if( (version/100)%100 != (ANGELSCRIPT_VERSION/100)%100 )
  152. return 0;
  153. if( (version%100) > (ANGELSCRIPT_VERSION%100) )
  154. return 0;
  155. // Verify the size of the types
  156. asASSERT( sizeof(asBYTE) == 1 );
  157. asASSERT( sizeof(asWORD) == 2 );
  158. asASSERT( sizeof(asDWORD) == 4 );
  159. asASSERT( sizeof(asQWORD) == 8 );
  160. asASSERT( sizeof(asPWORD) == sizeof(void*) );
  161. // Verify the boolean type
  162. asASSERT( sizeof(bool) == AS_SIZEOF_BOOL );
  163. asASSERT( true == VALUE_OF_BOOLEAN_TRUE );
  164. // Verify endianess
  165. #ifdef AS_BIG_ENDIAN
  166. asASSERT( *(asDWORD*)"\x00\x01\x02\x03" == 0x00010203 );
  167. asASSERT( *(asQWORD*)"\x00\x01\x02\x03\x04\x05\x06\x07" == I64(0x0001020304050607) );
  168. #else
  169. asASSERT( *(asDWORD*)"\x00\x01\x02\x03" == 0x03020100 );
  170. asASSERT( *(asQWORD*)"\x00\x01\x02\x03\x04\x05\x06\x07" == I64(0x0706050403020100) );
  171. #endif
  172. return asNEW(asCScriptEngine)();
  173. }
  174. int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value)
  175. {
  176. switch( property )
  177. {
  178. case asEP_ALLOW_UNSAFE_REFERENCES:
  179. ep.allowUnsafeReferences = value ? true : false;
  180. break;
  181. case asEP_OPTIMIZE_BYTECODE:
  182. ep.optimizeByteCode = value ? true : false;
  183. break;
  184. case asEP_COPY_SCRIPT_SECTIONS:
  185. ep.copyScriptSections = value ? true : false;
  186. break;
  187. case asEP_MAX_STACK_SIZE:
  188. // The size is given in bytes, but we only store dwords
  189. ep.maximumContextStackSize = (int)value/4;
  190. if( initialContextStackSize > ep.maximumContextStackSize )
  191. initialContextStackSize = ep.maximumContextStackSize;
  192. break;
  193. case asEP_USE_CHARACTER_LITERALS:
  194. ep.useCharacterLiterals = value ? true : false;
  195. break;
  196. case asEP_ALLOW_MULTILINE_STRINGS:
  197. ep.allowMultilineStrings = value ? true : false;
  198. break;
  199. case asEP_ALLOW_IMPLICIT_HANDLE_TYPES:
  200. ep.allowImplicitHandleTypes = value ? true : false;
  201. break;
  202. case asEP_BUILD_WITHOUT_LINE_CUES:
  203. ep.buildWithoutLineCues = value ? true : false;
  204. break;
  205. case asEP_INIT_GLOBAL_VARS_AFTER_BUILD:
  206. ep.initGlobalVarsAfterBuild = value ? true : false;
  207. break;
  208. case asEP_REQUIRE_ENUM_SCOPE:
  209. ep.requireEnumScope = value ? true : false;
  210. break;
  211. case asEP_SCRIPT_SCANNER:
  212. if( value <= 1 )
  213. ep.scanner = (int)value;
  214. else
  215. return asINVALID_ARG;
  216. break;
  217. case asEP_INCLUDE_JIT_INSTRUCTIONS:
  218. ep.includeJitInstructions = value ? true : false;
  219. break;
  220. case asEP_STRING_ENCODING:
  221. if( value <= 1 )
  222. ep.stringEncoding = (int)value;
  223. else
  224. return asINVALID_ARG;
  225. break;
  226. default:
  227. return asINVALID_ARG;
  228. }
  229. return asSUCCESS;
  230. }
  231. asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property)
  232. {
  233. switch( property )
  234. {
  235. case asEP_ALLOW_UNSAFE_REFERENCES:
  236. return ep.allowUnsafeReferences;
  237. case asEP_OPTIMIZE_BYTECODE:
  238. return ep.optimizeByteCode;
  239. case asEP_COPY_SCRIPT_SECTIONS:
  240. return ep.copyScriptSections;
  241. case asEP_MAX_STACK_SIZE:
  242. return ep.maximumContextStackSize*4;
  243. case asEP_USE_CHARACTER_LITERALS:
  244. return ep.useCharacterLiterals;
  245. case asEP_ALLOW_MULTILINE_STRINGS:
  246. return ep.allowMultilineStrings;
  247. case asEP_ALLOW_IMPLICIT_HANDLE_TYPES:
  248. return ep.allowImplicitHandleTypes;
  249. case asEP_BUILD_WITHOUT_LINE_CUES:
  250. return ep.buildWithoutLineCues;
  251. case asEP_INIT_GLOBAL_VARS_AFTER_BUILD:
  252. return ep.initGlobalVarsAfterBuild;
  253. case asEP_REQUIRE_ENUM_SCOPE:
  254. return ep.requireEnumScope;
  255. case asEP_SCRIPT_SCANNER:
  256. return ep.scanner;
  257. case asEP_INCLUDE_JIT_INSTRUCTIONS:
  258. return ep.includeJitInstructions;
  259. case asEP_STRING_ENCODING:
  260. return ep.stringEncoding;
  261. }
  262. return 0;
  263. }
  264. } // extern "C"
  265. asCScriptEngine::asCScriptEngine()
  266. {
  267. // Instanciate the thread manager
  268. if( threadManager == 0 )
  269. threadManager = asNEW(asCThreadManager);
  270. else
  271. threadManager->AddRef();
  272. // Engine properties
  273. ep.allowUnsafeReferences = false;
  274. ep.optimizeByteCode = true;
  275. ep.copyScriptSections = true;
  276. ep.maximumContextStackSize = 0; // no limit
  277. ep.useCharacterLiterals = false;
  278. ep.allowMultilineStrings = false;
  279. ep.allowImplicitHandleTypes = false;
  280. ep.buildWithoutLineCues = false;
  281. ep.initGlobalVarsAfterBuild = true;
  282. ep.requireEnumScope = false;
  283. ep.scanner = 1; // utf8. 0 = ascii
  284. ep.includeJitInstructions = false;
  285. ep.stringEncoding = 0; // utf8. 1 = utf16
  286. gc.engine = this;
  287. refCount.set(1);
  288. stringFactory = 0;
  289. configFailed = false;
  290. isPrepared = false;
  291. isBuilding = false;
  292. lastModule = 0;
  293. userData = 0;
  294. initialContextStackSize = 1024; // 1 KB
  295. typeIdSeqNbr = 0;
  296. currentGroup = &defaultGroup;
  297. msgCallback = 0;
  298. jitCompiler = 0;
  299. // Reserve function id 0 for no function
  300. scriptFunctions.PushLast(0);
  301. // Make sure typeId for the built-in primitives are defined according to asETypeIdFlags
  302. int id;
  303. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)); asASSERT( id == asTYPEID_VOID );
  304. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)); asASSERT( id == asTYPEID_BOOL );
  305. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)); asASSERT( id == asTYPEID_INT8 );
  306. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)); asASSERT( id == asTYPEID_INT16 );
  307. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)); asASSERT( id == asTYPEID_INT32 );
  308. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)); asASSERT( id == asTYPEID_INT64 );
  309. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)); asASSERT( id == asTYPEID_UINT8 );
  310. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)); asASSERT( id == asTYPEID_UINT16 );
  311. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)); asASSERT( id == asTYPEID_UINT32 );
  312. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)); asASSERT( id == asTYPEID_UINT64 );
  313. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)); asASSERT( id == asTYPEID_FLOAT );
  314. id = GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)); asASSERT( id == asTYPEID_DOUBLE );
  315. defaultArrayObjectType = 0;
  316. RegisterArrayObject(this);
  317. RegisterScriptObject(this);
  318. RegisterScriptFunction(this);
  319. RegisterObjectTypeGCBehaviours(this);
  320. }
  321. asCScriptEngine::~asCScriptEngine()
  322. {
  323. asASSERT(refCount.get() == 0);
  324. asUINT n;
  325. // The modules must be deleted first, as they may use
  326. // object types from the config groups
  327. for( n = (asUINT)scriptModules.GetLength(); n-- > 0; )
  328. {
  329. if( scriptModules[n] )
  330. {
  331. asDELETE(scriptModules[n],asCModule);
  332. }
  333. }
  334. scriptModules.SetLength(0);
  335. GarbageCollect(asGC_FULL_CYCLE);
  336. // Delete the functions for template types that may references object types
  337. for( n = 0; n < templateTypes.GetLength(); n++ )
  338. {
  339. if( templateTypes[n] )
  340. {
  341. asUINT f;
  342. // Delete the factory stubs first
  343. for( f = 0; f < templateTypes[n]->beh.factories.GetLength(); f++ )
  344. {
  345. scriptFunctions[templateTypes[n]->beh.factories[f]]->Release();
  346. }
  347. templateTypes[n]->beh.factories.Allocate(0, false);
  348. // Delete the specialized functions
  349. for( f = 1; f < templateTypes[n]->beh.operators.GetLength(); f += 2 )
  350. {
  351. if( scriptFunctions[templateTypes[n]->beh.operators[f]]->objectType == templateTypes[n] )
  352. {
  353. scriptFunctions[templateTypes[n]->beh.operators[f]]->Release();
  354. templateTypes[n]->beh.operators[f] = 0;
  355. }
  356. }
  357. }
  358. }
  359. // Do one more garbage collect to free gc objects that were global variables
  360. GarbageCollect(asGC_FULL_CYCLE);
  361. FreeUnusedGlobalProperties();
  362. ClearUnusedTypes();
  363. // Break all relationship between remaining class types and functions
  364. for( n = 0; n < classTypes.GetLength(); n++ )
  365. {
  366. if( classTypes[n] )
  367. classTypes[n]->ReleaseAllFunctions();
  368. if( classTypes[n]->derivedFrom )
  369. {
  370. classTypes[n]->derivedFrom->Release();
  371. classTypes[n]->derivedFrom = 0;
  372. }
  373. }
  374. GarbageCollect(asGC_FULL_CYCLE);
  375. FreeUnusedGlobalProperties();
  376. ClearUnusedTypes();
  377. asSMapNode<int,asCDataType*> *cursor = 0;
  378. while( mapTypeIdToDataType.MoveFirst(&cursor) )
  379. {
  380. asDELETE(mapTypeIdToDataType.GetValue(cursor),asCDataType);
  381. mapTypeIdToDataType.Erase(cursor);
  382. }
  383. defaultGroup.RemoveConfiguration(this);
  384. while( configGroups.GetLength() )
  385. {
  386. // Delete config groups in the right order
  387. asCConfigGroup *grp = configGroups.PopLast();
  388. if( grp )
  389. {
  390. asDELETE(grp,asCConfigGroup);
  391. }
  392. }
  393. for( n = 0; n < registeredGlobalProps.GetLength(); n++ )
  394. {
  395. if( registeredGlobalProps[n] )
  396. {
  397. asDELETE(registeredGlobalProps[n],asCGlobalProperty);
  398. }
  399. }
  400. registeredGlobalProps.SetLength(0);
  401. FreeUnusedGlobalProperties();
  402. for( n = 0; n < templateTypes.GetLength(); n++ )
  403. {
  404. if( templateTypes[n] )
  405. {
  406. // Clear the sub type before deleting the template type so that the sub type isn't freed to soon
  407. templateTypes[n]->templateSubType = asCDataType::CreateNullHandle();
  408. asDELETE(templateTypes[n],asCObjectType);
  409. }
  410. }
  411. templateTypes.SetLength(0);
  412. for( n = 0; n < objectTypes.GetLength(); n++ )
  413. {
  414. if( objectTypes[n] )
  415. {
  416. // Clear the sub type before deleting the template type so that the sub type isn't freed to soon
  417. objectTypes[n]->templateSubType = asCDataType::CreateNullHandle();
  418. asDELETE(objectTypes[n],asCObjectType);
  419. }
  420. }
  421. objectTypes.SetLength(0);
  422. for( n = 0; n < templateSubTypes.GetLength(); n++ )
  423. {
  424. if( templateSubTypes[n] )
  425. {
  426. asDELETE(templateSubTypes[n], asCObjectType);
  427. }
  428. }
  429. templateSubTypes.SetLength(0);
  430. registeredTypeDefs.SetLength(0);
  431. registeredEnums.SetLength(0);
  432. registeredObjTypes.SetLength(0);
  433. for( n = 0; n < registeredGlobalFuncs.GetLength(); n++ )
  434. {
  435. if( registeredGlobalFuncs[n] )
  436. registeredGlobalFuncs[n]->Release();
  437. }
  438. registeredGlobalFuncs.SetLength(0);
  439. scriptTypeBehaviours.ReleaseAllFunctions();
  440. functionBehaviours.ReleaseAllFunctions();
  441. objectTypeBehaviours.ReleaseAllFunctions();
  442. // Free string constants
  443. for( n = 0; n < stringConstants.GetLength(); n++ )
  444. {
  445. asDELETE(stringConstants[n],asCString);
  446. }
  447. stringConstants.SetLength(0);
  448. // Free the script section names
  449. for( n = 0; n < scriptSectionNames.GetLength(); n++ )
  450. {
  451. asDELETE(scriptSectionNames[n],asCString);
  452. }
  453. scriptSectionNames.SetLength(0);
  454. // Release the thread manager
  455. threadManager->Release();
  456. }
  457. // interface
  458. int asCScriptEngine::AddRef()
  459. {
  460. return refCount.atomicInc();
  461. }
  462. // interface
  463. int asCScriptEngine::Release()
  464. {
  465. int r = refCount.atomicDec();
  466. if( r == 0 )
  467. {
  468. asDELETE(this,asCScriptEngine);
  469. return 0;
  470. }
  471. return r;
  472. }
  473. // interface
  474. void *asCScriptEngine::SetUserData(void *data)
  475. {
  476. void *old = userData;
  477. userData = data;
  478. return old;
  479. }
  480. // interface
  481. void *asCScriptEngine::GetUserData()
  482. {
  483. return userData;
  484. }
  485. // interface
  486. int asCScriptEngine::SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)
  487. {
  488. msgCallback = true;
  489. msgCallbackObj = obj;
  490. bool isObj = false;
  491. if( (unsigned)callConv == asCALL_GENERIC )
  492. {
  493. msgCallback = false;
  494. return asNOT_SUPPORTED;
  495. }
  496. if( (unsigned)callConv >= asCALL_THISCALL )
  497. {
  498. isObj = true;
  499. if( obj == 0 )
  500. {
  501. msgCallback = false;
  502. return asINVALID_ARG;
  503. }
  504. }
  505. int r = DetectCallingConvention(isObj, callback, callConv, &msgCallbackFunc);
  506. if( r < 0 ) msgCallback = false;
  507. return r;
  508. }
  509. // interface
  510. int asCScriptEngine::ClearMessageCallback()
  511. {
  512. msgCallback = false;
  513. return 0;
  514. }
  515. // interface
  516. int asCScriptEngine::WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message)
  517. {
  518. // Validate input parameters
  519. if( section == 0 ||
  520. message == 0 )
  521. return asINVALID_ARG;
  522. // If there is no callback then there's nothing to do
  523. if( !msgCallback )
  524. return 0;
  525. asSMessageInfo msg;
  526. msg.section = section;
  527. msg.row = row;
  528. msg.col = col;
  529. msg.type = type;
  530. msg.message = message;
  531. if( msgCallbackFunc.callConv < ICC_THISCALL )
  532. CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0);
  533. else
  534. CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0);
  535. return 0;
  536. }
  537. int asCScriptEngine::SetJITCompiler(asIJITCompiler *compiler)
  538. {
  539. jitCompiler = compiler;
  540. return asSUCCESS;
  541. }
  542. asIJITCompiler *asCScriptEngine::GetJITCompiler()
  543. {
  544. return jitCompiler;
  545. }
  546. // interface
  547. asETokenClass asCScriptEngine::ParseToken(const char *string, size_t stringLength, int *tokenLength)
  548. {
  549. if( stringLength == 0 )
  550. stringLength = strlen(string);
  551. size_t len;
  552. asCTokenizer t;
  553. asETokenClass tc;
  554. t.GetToken(string, stringLength, &len, &tc);
  555. if( tokenLength )
  556. *tokenLength = (int)len;
  557. return tc;
  558. }
  559. // interface
  560. asIScriptModule *asCScriptEngine::GetModule(const char *module, asEGMFlags flag)
  561. {
  562. asCModule *mod = GetModule(module, false);
  563. if( flag == asGM_ALWAYS_CREATE )
  564. {
  565. if( mod != 0 )
  566. {
  567. asDELETE(mod, asCModule);
  568. }
  569. return GetModule(module, true);
  570. }
  571. if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS )
  572. {
  573. return GetModule(module, true);
  574. }
  575. return mod;
  576. }
  577. // interface
  578. int asCScriptEngine::DiscardModule(const char *module)
  579. {
  580. asCModule *mod = GetModule(module, false);
  581. if( mod == 0 ) return asNO_MODULE;
  582. asDELETE(mod, asCModule);
  583. FreeUnusedGlobalProperties();
  584. ClearUnusedTypes();
  585. return 0;
  586. }
  587. void asCScriptEngine::ClearUnusedTypes()
  588. {
  589. // Build a list of all types to check for
  590. asCArray<asCObjectType*> types;
  591. types = classTypes;
  592. types.Concatenate(templateInstanceTypes);
  593. // Go through all modules
  594. asUINT n;
  595. for( n = 0; n < scriptModules.GetLength() && types.GetLength(); n++ )
  596. {
  597. asCModule *mod = scriptModules[n];
  598. if( mod )
  599. {
  600. // Functions/Methods/Globals are handled after this
  601. // Go through all type declarations
  602. asUINT m;
  603. for( m = 0; m < mod->classTypes.GetLength() && types.GetLength(); m++ )
  604. RemoveTypeAndRelatedFromList(types, mod->classTypes[m]);
  605. for( m = 0; m < mod->enumTypes.GetLength() && types.GetLength(); m++ )
  606. RemoveTypeAndRelatedFromList(types, mod->enumTypes[m]);
  607. for( m = 0; m < mod->typeDefs.GetLength() && types.GetLength(); m++ )
  608. RemoveTypeAndRelatedFromList(types, mod->typeDefs[m]);
  609. }
  610. }
  611. // Go through all function parameters and remove used types
  612. for( n = 0; n < scriptFunctions.GetLength() && types.GetLength(); n++ )
  613. {
  614. asCScriptFunction *func = scriptFunctions[n];
  615. if( func )
  616. {
  617. // Ignore factory stubs
  618. if( func->name == "factstub" )
  619. continue;
  620. asCObjectType *ot = func->returnType.GetObjectType();
  621. if( ot != 0 && ot != func->objectType )
  622. if( func->name != ot->name )
  623. RemoveTypeAndRelatedFromList(types, ot);
  624. for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
  625. {
  626. ot = func->parameterTypes[p].GetObjectType();
  627. if( ot != 0 && ot != func->objectType )
  628. if( func->name != ot->name )
  629. RemoveTypeAndRelatedFromList(types, ot);
  630. }
  631. }
  632. }
  633. // Go through all global properties
  634. for( n = 0; n < globalProperties.GetLength() && types.GetLength(); n++ )
  635. {
  636. if( globalProperties[n] && globalProperties[n]->type.GetObjectType() )
  637. RemoveTypeAndRelatedFromList(types, globalProperties[n]->type.GetObjectType());
  638. }
  639. // All that remains in the list after this can be discarded, since they are no longer used
  640. for(;;)
  641. {
  642. bool didClearTemplateInstanceType = false;
  643. for( n = 0; n < types.GetLength(); n++ )
  644. {
  645. // Template types and script classes will have two references for each factory stub
  646. int refCount = ((types[n]->flags & asOBJ_TEMPLATE) || (types[n]->flags & asOBJ_SCRIPT_OBJECT)) ? 2*(int)types[n]->beh.factories.GetLength() : 0;
  647. if( types[n]->GetRefCount() == refCount )
  648. {
  649. if( types[n]->flags & asOBJ_TEMPLATE )
  650. {
  651. didClearTemplateInstanceType = true;
  652. RemoveTemplateInstanceType(types[n]);
  653. }
  654. else
  655. {
  656. RemoveFromTypeIdMap(types[n]);
  657. asDELETE(types[n],asCObjectType);
  658. int i = classTypes.IndexOf(types[n]);
  659. if( i == (signed)classTypes.GetLength() - 1 )
  660. classTypes.PopLast();
  661. else
  662. classTypes[i] = classTypes.PopLast();
  663. }
  664. // Remove the type from the array
  665. if( n < types.GetLength() - 1 )
  666. types[n] = types.PopLast();
  667. else
  668. types.PopLast();
  669. n--;
  670. }
  671. }
  672. if( didClearTemplateInstanceType == false )
  673. break;
  674. }
  675. }
  676. void asCScriptEngine::RemoveTypeAndRelatedFromList(asCArray<asCObjectType*> &types, asCObjectType *ot)
  677. {
  678. // Remove the type from the list
  679. int i = types.IndexOf(ot);
  680. if( i == -1 ) return;
  681. if( i == (signed)types.GetLength() - 1 )
  682. types.PopLast();
  683. else
  684. types[i] = types.PopLast();
  685. // If the type is an template type, then remove all sub types as well
  686. if( ot->templateSubType.GetObjectType() )
  687. {
  688. while( ot->templateSubType.GetObjectType() )
  689. {
  690. ot = ot->templateSubType.GetObjectType();
  691. RemoveTypeAndRelatedFromList(types, ot);
  692. }
  693. return;
  694. }
  695. // If the type is a class, then remove all properties types as well
  696. if( ot->properties.GetLength() )
  697. {
  698. for( asUINT n = 0; n < ot->properties.GetLength(); n++ )
  699. RemoveTypeAndRelatedFromList(types, ot->properties[n]->type.GetObjectType());
  700. }
  701. }
  702. // internal
  703. int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl)
  704. {
  705. asCModule *mod = 0;
  706. // Is this a script class?
  707. if( ot->flags & asOBJ_SCRIPT_OBJECT && ot->size > 0 )
  708. mod = scriptFunctions[ot->beh.factory]->module;
  709. asCBuilder bld(this, mod);
  710. asCScriptFunction func(this, mod,-1);
  711. int r = bld.ParseFunctionDeclaration(0, decl, &func, false);
  712. if( r < 0 )
  713. return asINVALID_DECLARATION;
  714. // Search for matching factory function
  715. int id = -1;
  716. for( size_t n = 0; n < ot->beh.factories.GetLength(); n++ )
  717. {
  718. asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]];
  719. if( f->IsSignatureEqual(&func) )
  720. {
  721. id = ot->beh.factories[n];
  722. break;
  723. }
  724. }
  725. if( id == -1 ) return asNO_FUNCTION;
  726. return id;
  727. }
  728. // internal
  729. int asCScriptEngine::GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod)
  730. {
  731. asCBuilder bld(this, mod);
  732. asCScriptFunction func(this, mod, -1);
  733. int r = bld.ParseFunctionDeclaration(0, decl, &func, false);
  734. if( r < 0 )
  735. return asINVALID_DECLARATION;
  736. // Set the object type so that the signature can be properly compared
  737. // This cast is OK, it will only be used for comparison
  738. func.objectType = const_cast<asCObjectType*>(ot);
  739. // Search script functions for matching interface
  740. int id = -1;
  741. for( size_t n = 0; n < ot->methods.GetLength(); ++n )
  742. {
  743. if( func.IsSignatureEqual(scriptFunctions[ot->methods[n]]) )
  744. {
  745. if( id == -1 )
  746. id = ot->methods[n];
  747. else
  748. return asMULTIPLE_FUNCTIONS;
  749. }
  750. }
  751. if( id == -1 ) return asNO_FUNCTION;
  752. return id;
  753. }
  754. // Internal
  755. asCString asCScriptEngine::GetFunctionDeclaration(int funcID)
  756. {
  757. asCString str;
  758. asCScriptFunction *func = GetScriptFunction(funcID);
  759. if( func )
  760. str = func->GetDeclarationStr();
  761. return str;
  762. }
  763. asCScriptFunction *asCScriptEngine::GetScriptFunction(int funcId)
  764. {
  765. if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() )
  766. return 0;
  767. return scriptFunctions[funcId];
  768. }
  769. asIScriptContext *asCScriptEngine::CreateContext()
  770. {
  771. asIScriptContext *ctx = 0;
  772. CreateContext(&ctx, false);
  773. return ctx;
  774. }
  775. int asCScriptEngine::CreateContext(asIScriptContext **context, bool isInternal)
  776. {
  777. *context = asNEW(asCContext)(this, !isInternal);
  778. // We need to make sure the engine has been
  779. // prepared before any context is executed
  780. PrepareEngine();
  781. return 0;
  782. }
  783. int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset)
  784. {
  785. int r;
  786. asCDataType dt;
  787. asCBuilder bld(this, 0);
  788. r = bld.ParseDataType(obj, &dt);
  789. if( r < 0 )
  790. return ConfigError(r);
  791. // Verify that the correct config group is used
  792. if( currentGroup->FindType(dt.GetObjectType()->name.AddressOf()) == 0 )
  793. return ConfigError(asWRONG_CONFIG_GROUP);
  794. asCDataType type;
  795. asCString name;
  796. if( (r = bld.VerifyProperty(&dt, declaration, name, type)) < 0 )
  797. return ConfigError(r);
  798. // Store the property info
  799. if( dt.GetObjectType() == 0 )
  800. return ConfigError(asINVALID_OBJECT);
  801. asCObjectProperty *prop = asNEW(asCObjectProperty);
  802. prop->name = name;
  803. prop->type = type;
  804. prop->byteOffset = byteOffset;
  805. dt.GetObjectType()->properties.PushLast(prop);
  806. currentGroup->RefConfigGroup(FindConfigGroupForObjectType(type.GetObjectType()));
  807. return asSUCCESS;
  808. }
  809. int asCScriptEngine::RegisterInterface(const char *name)
  810. {
  811. if( name == 0 ) return ConfigError(asINVALID_NAME);
  812. // Verify if the name has been registered as a type already
  813. asUINT n;
  814. for( n = 0; n < objectTypes.GetLength(); n++ )
  815. {
  816. if( objectTypes[n] && objectTypes[n]->name == name )
  817. return asALREADY_REGISTERED;
  818. }
  819. // Use builder to parse the datatype
  820. asCDataType dt;
  821. asCBuilder bld(this, 0);
  822. bool oldMsgCallback = msgCallback; msgCallback = false;
  823. int r = bld.ParseDataType(name, &dt);
  824. msgCallback = oldMsgCallback;
  825. if( r >= 0 ) return ConfigError(asERROR);
  826. // Make sure the name is not a reserved keyword
  827. asCTokenizer t;
  828. size_t tokenLen;
  829. int token = t.GetToken(name, strlen(name), &tokenLen);
  830. if( token != ttIdentifier || strlen(name) != tokenLen )
  831. return ConfigError(asINVALID_NAME);
  832. r = bld.CheckNameConflict(name, 0, 0);
  833. if( r < 0 )
  834. return ConfigError(asNAME_TAKEN);
  835. // Don't have to check against members of object
  836. // types as they are allowed to use the names
  837. // Register the object type for the interface
  838. asCObjectType *st = asNEW(asCObjectType)(this);
  839. st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
  840. st->size = 0; // Cannot be instanciated
  841. st->name = name;
  842. // Use the default script class behaviours
  843. st->beh.factory = 0;
  844. st->beh.addref = scriptTypeBehaviours.beh.addref;
  845. scriptFunctions[st->beh.addref]->AddRef();
  846. st->beh.release = scriptTypeBehaviours.beh.release;
  847. scriptFunctions[st->beh.release]->AddRef();
  848. st->beh.copy = 0;
  849. objectTypes.PushLast(st);
  850. registeredObjTypes.PushLast(st);
  851. currentGroup->objTypes.PushLast(st);
  852. return asSUCCESS;
  853. }
  854. int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *declaration)
  855. {
  856. // Verify that the correct config group is set.
  857. if( currentGroup->FindType(intf) == 0 )
  858. return ConfigError(asWRONG_CONFIG_GROUP);
  859. asCDataType dt;
  860. asCBuilder bld(this, 0);
  861. int r = bld.ParseDataType(intf, &dt);
  862. if( r < 0 )
  863. return ConfigError(r);
  864. asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_INTERFACE);
  865. func->objectType = dt.GetObjectType();
  866. r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, false);
  867. if( r < 0 )
  868. {
  869. asDELETE(func,asCScriptFunction);
  870. return ConfigError(asINVALID_DECLARATION);
  871. }
  872. // Check name conflicts
  873. r = bld.CheckNameConflictMember(dt, func->name.AddressOf(), 0, 0);
  874. if( r < 0 )
  875. {
  876. asDELETE(func,asCScriptFunction);
  877. return ConfigError(asNAME_TAKEN);
  878. }
  879. func->id = GetNextScriptFunctionId();
  880. SetScriptFunction(func);
  881. func->objectType->methods.PushLast(func->id);
  882. // The refCount was already set to 1
  883. func->ComputeSignatureId();
  884. // If parameter type from other groups are used, add references
  885. // TODO: The code for adding references to config groups is repeated in a lot of places
  886. if( func->returnType.GetObjectType() )
  887. {
  888. asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType());
  889. currentGroup->RefConfigGroup(group);
  890. }
  891. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  892. {
  893. if( func->parameterTypes[n].GetObjectType() )
  894. {
  895. asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType());
  896. currentGroup->RefConfigGroup(group);
  897. }
  898. }
  899. // Return function id as success
  900. return func->id;
  901. }
  902. int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD flags)
  903. {
  904. int r;
  905. isPrepared = false;
  906. // Verify flags
  907. // Must have either asOBJ_REF or asOBJ_VALUE
  908. if( flags & asOBJ_REF )
  909. {
  910. // Can optionally have the asOBJ_GC, asOBJ_NOHANDLE, asOBJ_SCOPED, or asOBJ_TEMPLATE flag set, but nothing else
  911. if( flags & ~(asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_TEMPLATE) )
  912. return ConfigError(asINVALID_ARG);
  913. // flags are exclusive
  914. if( (flags & asOBJ_GC) && (flags & (asOBJ_NOHANDLE|asOBJ_SCOPED)) )
  915. return ConfigError(asINVALID_ARG);
  916. if( (flags & asOBJ_NOHANDLE) && (flags & (asOBJ_GC|asOBJ_SCOPED)) )
  917. return ConfigError(asINVALID_ARG);
  918. if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE)) )
  919. return ConfigError(asINVALID_ARG);
  920. }
  921. else if( flags & asOBJ_VALUE )
  922. {
  923. // Cannot use reference flags
  924. // TODO: template: Should be possible to register a value type as template type
  925. if( flags & (asOBJ_REF | asOBJ_GC | asOBJ_SCOPED) )
  926. return ConfigError(asINVALID_ARG);
  927. // If the app type is given, we must validate the flags
  928. if( flags & asOBJ_APP_CLASS )
  929. {
  930. // Must not set the primitive or float flag
  931. if( flags & (asOBJ_APP_PRIMITIVE |
  932. asOBJ_APP_FLOAT) )
  933. return ConfigError(asINVALID_ARG);
  934. }
  935. else if( flags & asOBJ_APP_PRIMITIVE )
  936. {
  937. // Must not set the class flags nor the float flag
  938. if( flags & (asOBJ_APP_CLASS |
  939. asOBJ_APP_CLASS_CONSTRUCTOR |
  940. asOBJ_APP_CLASS_DESTRUCTOR |
  941. asOBJ_APP_CLASS_ASSIGNMENT |
  942. asOBJ_APP_FLOAT) )
  943. return ConfigError(asINVALID_ARG);
  944. }
  945. else if( flags & asOBJ_APP_FLOAT )
  946. {
  947. // Must not set the class flags nor the primitive flag
  948. if( flags & (asOBJ_APP_CLASS |
  949. asOBJ_APP_CLASS_CONSTRUCTOR |
  950. asOBJ_APP_CLASS_DESTRUCTOR |
  951. asOBJ_APP_CLASS_ASSIGNMENT |
  952. asOBJ_APP_PRIMITIVE) )
  953. return ConfigError(asINVALID_ARG);
  954. }
  955. else if( flags & (asOBJ_APP_CLASS_CONSTRUCTOR |
  956. asOBJ_APP_CLASS_DESTRUCTOR |
  957. asOBJ_APP_CLASS_ASSIGNMENT) )
  958. {
  959. // Must not set the class properties, without the class flag
  960. return ConfigError(asINVALID_ARG);
  961. }
  962. }
  963. else
  964. return ConfigError(asINVALID_ARG);
  965. // Don't allow anything else than the defined flags
  966. if( flags - (flags & asOBJ_MASK_VALID_FLAGS) )
  967. return ConfigError(asINVALID_ARG);
  968. // Value types must have a defined size
  969. if( (flags & asOBJ_VALUE) && byteSize == 0 )
  970. {
  971. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_VALUE_TYPE_MUST_HAVE_SIZE);
  972. return ConfigError(asINVALID_ARG);
  973. }
  974. // Verify type name
  975. if( name == 0 )
  976. return ConfigError(asINVALID_NAME);
  977. asCString typeName;
  978. asCBuilder bld(this, 0);
  979. if( flags & asOBJ_TEMPLATE )
  980. {
  981. asCString subtypeName;
  982. r = bld.ParseTemplateDecl(name, &typeName, &subtypeName);
  983. if( r < 0 )
  984. return r;
  985. // Verify that the template name hasn't been registered as a type already
  986. asUINT n;
  987. for( n = 0; n < objectTypes.GetLength(); n++ )
  988. {
  989. if( objectTypes[n] && objectTypes[n]->name == typeName )
  990. return asALREADY_REGISTERED;
  991. }
  992. asCObjectType *type = asNEW(asCObjectType)(this);
  993. type->name = typeName;
  994. type->size = byteSize;
  995. type->flags = flags;
  996. // Store it in the object types
  997. objectTypes.PushLast(type);
  998. // Define a template subtype
  999. asCObjectType *subtype = 0;
  1000. for( n = 0; n < templateSubTypes.GetLength(); n++ )
  1001. {
  1002. if( templateSubTypes[n]->name == subtypeName )
  1003. {
  1004. subtype = templateSubTypes[n];
  1005. break;
  1006. }
  1007. }
  1008. if( subtype == 0 )
  1009. {
  1010. // Create the new subtype if not already existing
  1011. subtype = asNEW(asCObjectType)(this);
  1012. subtype->name = subtypeName;
  1013. subtype->size = 0;
  1014. subtype->flags = asOBJ_TEMPLATE_SUBTYPE;
  1015. templateSubTypes.PushLast(subtype);
  1016. subtype->AddRef();
  1017. }
  1018. type->templateSubType = asCDataType::CreateObject(subtype, false);
  1019. subtype->AddRef();
  1020. currentGroup->objTypes.PushLast(type);
  1021. if( defaultArrayObjectType == 0 )
  1022. {
  1023. // TODO: The default array object type should be defined by the application
  1024. // The default array object type is registered by the engine itself
  1025. defaultArrayObjectType = type;
  1026. type->AddRef();
  1027. }
  1028. else
  1029. {
  1030. registeredObjTypes.PushLast(type);
  1031. }
  1032. }
  1033. else
  1034. {
  1035. typeName = name;
  1036. // Verify if the name has been registered as a type already
  1037. asUINT n;
  1038. for( n = 0; n < objectTypes.GetLength(); n++ )
  1039. {
  1040. if( objectTypes[n] && objectTypes[n]->name == typeName )
  1041. return asALREADY_REGISTERED;
  1042. }
  1043. for( n = 0; n < templateTypes.GetLength(); n++ )
  1044. {
  1045. if( templateTypes[n] && templateTypes[n]->name == typeName )
  1046. return asALREADY_REGISTERED;
  1047. }
  1048. // Verify the most recently created template instance type
  1049. asCObjectType *mostRecentTemplateInstanceType = 0;
  1050. if( templateInstanceTypes.GetLength() )
  1051. mostRecentTemplateInstanceType = templateInstanceTypes[templateInstanceTypes.GetLength()-1];
  1052. // Use builder to parse the datatype
  1053. asCDataType dt;
  1054. bool oldMsgCallback = msgCallback; msgCallback = false;
  1055. r = bld.ParseDataType(name, &dt);
  1056. msgCallback = oldMsgCallback;
  1057. // If the builder fails, then the type name
  1058. // is new and it should be registered
  1059. if( r < 0 )
  1060. {
  1061. // Make sure the name is not a reserved keyword
  1062. asCTokenizer t;
  1063. size_t tokenLen;
  1064. int token = t.GetToken(name, typeName.GetLength(), &tokenLen);
  1065. if( token != ttIdentifier || typeName.GetLength() != tokenLen )
  1066. return ConfigError(asINVALID_NAME);
  1067. int r = bld.CheckNameConflict(name, 0, 0);
  1068. if( r < 0 )
  1069. return ConfigError(asNAME_TAKEN);
  1070. // Don't have to check against members of object
  1071. // types as they are allowed to use the names
  1072. // Put the data type in the list
  1073. asCObjectType *type = asNEW(asCObjectType)(this);
  1074. type->name = typeName;
  1075. type->size = byteSize;
  1076. type->flags = flags;
  1077. objectTypes.PushLast(type);
  1078. registeredObjTypes.PushLast(type);
  1079. currentGroup->objTypes.PushLast(type);
  1080. }
  1081. else
  1082. {
  1083. // The application is registering a template specialization so we
  1084. // need to replace the template instance type with the new type.
  1085. // TODO: Template: We don't require the lower dimensions to be registered first for registered template types
  1086. // int[][] must not be allowed to be registered
  1087. // if int[] hasn't been registered first
  1088. if( dt.GetSubType().IsTemplate() )
  1089. return ConfigError(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED);
  1090. if( dt.IsReadOnly() ||
  1091. dt.IsReference() )
  1092. return ConfigError(asINVALID_TYPE);
  1093. // Was the template instance type created before?
  1094. if( templateInstanceTypes[templateInstanceTypes.GetLength()-1] == mostRecentTemplateInstanceType ||
  1095. mostRecentTemplateInstanceType == dt.GetObjectType() )
  1096. // TODO: Should have a better error message
  1097. return ConfigError(asNOT_SUPPORTED);
  1098. // TODO: Add this again. The type is used by the factory stubs so we need to discount that
  1099. // Is the template instance type already being used?
  1100. // if( dt.GetObjectType()->GetRefCount() > 1 )
  1101. // return ConfigError(asNOT_SUPPORTED);
  1102. // Put the data type in the list
  1103. asCObjectType *type = asNEW(asCObjectType)(this);
  1104. type->name = dt.GetObjectType()->name;
  1105. type->templateSubType = dt.GetSubType();
  1106. if( type->templateSubType.GetObjectType() ) type->templateSubType.GetObjectType()->AddRef();
  1107. type->size = byteSize;
  1108. type->flags = flags;
  1109. templateTypes.PushLast(type);
  1110. currentGroup->objTypes.PushLast(type);
  1111. // Remove the template instance type, which will no longer be used.
  1112. RemoveTemplateInstanceType(dt.GetObjectType());
  1113. }
  1114. }
  1115. return asSUCCESS;
  1116. }
  1117. // interface
  1118. int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv)
  1119. {
  1120. if( datatype == 0 ) return ConfigError(asINVALID_ARG);
  1121. // Determine the object type
  1122. asCBuilder bld(this, 0);
  1123. asCDataType type;
  1124. int r = bld.ParseDataType(datatype, &type);
  1125. if( r < 0 )
  1126. return ConfigError(r);
  1127. if( type.GetObjectType() == 0 )
  1128. return ConfigError(asINVALID_TYPE);
  1129. if( type.IsReadOnly() || type.IsReference() )
  1130. return ConfigError(asINVALID_TYPE);
  1131. return RegisterBehaviourToObjectType(type.GetObjectType(), behaviour, decl, funcPointer, callConv);
  1132. }
  1133. // internal
  1134. int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv)
  1135. {
  1136. asSSystemFunctionInterface internal;
  1137. if( behaviour == asBEHAVE_FACTORY ||
  1138. behaviour == asBEHAVE_TEMPLATE_CALLBACK )
  1139. {
  1140. #ifdef AS_MAX_PORTABILITY
  1141. if( callConv != asCALL_GENERIC )
  1142. return ConfigError(asNOT_SUPPORTED);
  1143. #endif
  1144. int r = DetectCallingConvention(false, funcPointer, callConv, &internal);
  1145. if( r < 0 )
  1146. return ConfigError(r);
  1147. }
  1148. else
  1149. {
  1150. #ifdef AS_MAX_PORTABILITY
  1151. if( callConv != asCALL_GENERIC )
  1152. return ConfigError(asNOT_SUPPORTED);
  1153. #else
  1154. if( callConv != asCALL_THISCALL &&
  1155. callConv != asCALL_CDECL_OBJLAST &&
  1156. callConv != asCALL_CDECL_OBJFIRST &&
  1157. callConv != asCALL_GENERIC )
  1158. return ConfigError(asNOT_SUPPORTED);
  1159. #endif
  1160. int r = DetectCallingConvention(true, funcPointer, callConv, &internal);
  1161. if( r < 0 )
  1162. return ConfigError(r);
  1163. }
  1164. isPrepared = false;
  1165. asSTypeBehaviour *beh = &objectType->beh;
  1166. // Verify function declaration
  1167. asCScriptFunction func(this, 0, -1);
  1168. asCBuilder bld(this, 0);
  1169. int r = bld.ParseFunctionDeclaration(objectType, decl, &func, true, &internal.paramAutoHandles, &internal.returnAutoHandle);
  1170. if( r < 0 )
  1171. return ConfigError(asINVALID_DECLARATION);
  1172. func.name.Format("_beh_%d_", behaviour);
  1173. if( behaviour != asBEHAVE_FACTORY )
  1174. func.objectType = objectType;
  1175. // Check if the method restricts that use of the template to value types or reference types
  1176. if( objectType->flags & asOBJ_TEMPLATE )
  1177. {
  1178. if( func.returnType.GetObjectType() == objectType->templateSubType.GetObjectType() )
  1179. {
  1180. if( func.returnType.IsObjectHandle() )
  1181. objectType->acceptValueSubType = false;
  1182. else if( !func.returnType.IsReference() )
  1183. objectType->acceptRefSubType = false;
  1184. }
  1185. for( asUINT n = 0; n < func.parameterTypes.GetLength(); n++ )
  1186. {
  1187. if( func.parameterTypes[n].GetObjectType() == objectType->templateSubType.GetObjectType() )
  1188. {
  1189. // TODO: If unsafe references are allowed, then inout references allow value types
  1190. if( func.parameterTypes[n].IsObjectHandle() || (func.parameterTypes[n].IsReference() && func.inOutFlags[n] == asTM_INOUTREF) )
  1191. objectType->acceptValueSubType = false;
  1192. else if( !func.parameterTypes[n].IsReference() )
  1193. objectType->acceptRefSubType = false;
  1194. }
  1195. }
  1196. }
  1197. if( behaviour == asBEHAVE_CONSTRUCT )
  1198. {
  1199. // TODO: Add asBEHAVE_IMPLICIT_CONSTRUCT
  1200. // Verify that the return type is void
  1201. if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  1202. return ConfigError(asINVALID_DECLARATION);
  1203. if( objectType->flags & asOBJ_SCRIPT_OBJECT )
  1204. {
  1205. // The script object is a special case
  1206. asASSERT(func.parameterTypes.GetLength() == 1);
  1207. beh->construct = AddBehaviourFunction(func, internal);
  1208. beh->factory = beh->construct;
  1209. scriptFunctions[beh->factory]->AddRef();
  1210. beh->constructors.PushLast(beh->construct);
  1211. beh->factories.PushLast(beh->factory);
  1212. func.id = beh->construct;
  1213. }
  1214. else
  1215. {
  1216. // Verify that it is a value type
  1217. if( !(func.objectType->flags & asOBJ_VALUE) )
  1218. {
  1219. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1220. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1221. }
  1222. // Implicit constructors must take one and only one parameter
  1223. /* if( behaviour == asBEHAVE_IMPLICIT_CONSTRUCT &&
  1224. func.parameterTypes.GetLength() != 1 )
  1225. return ConfigError(asINVALID_DECLARATION);
  1226. */
  1227. // TODO: Verify that the same constructor hasn't been registered already
  1228. // Store all constructors in a list
  1229. if( func.parameterTypes.GetLength() == 0 )
  1230. {
  1231. func.id = beh->construct = AddBehaviourFunction(func, internal);
  1232. beh->constructors.PushLast(beh->construct);
  1233. }
  1234. else
  1235. {
  1236. func.id = AddBehaviourFunction(func, internal);
  1237. beh->constructors.PushLast(func.id);
  1238. /*
  1239. if( behaviour == asBEHAVE_IMPLICIT_CONSTRUCT )
  1240. {
  1241. beh->operators.PushLast(behaviour);
  1242. beh->operators.PushLast(func.id);
  1243. }
  1244. */ }
  1245. }
  1246. }
  1247. else if( behaviour == asBEHAVE_DESTRUCT )
  1248. {
  1249. // Must be a value type
  1250. if( !(func.objectType->flags & asOBJ_VALUE) )
  1251. {
  1252. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1253. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1254. }
  1255. if( beh->destruct )
  1256. return ConfigError(asALREADY_REGISTERED);
  1257. // Verify that the return type is void
  1258. if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  1259. return ConfigError(asINVALID_DECLARATION);
  1260. // Verify that there are no parameters
  1261. if( func.parameterTypes.GetLength() > 0 )
  1262. return ConfigError(asINVALID_DECLARATION);
  1263. func.id = beh->destruct = AddBehaviourFunction(func, internal);
  1264. }
  1265. else if( behaviour == asBEHAVE_FACTORY )
  1266. {
  1267. // TODO: Add asBEHAVE_IMPLICIT_FACTORY
  1268. // Must be a ref type and must not have asOBJ_NOHANDLE
  1269. if( !(objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_NOHANDLE) )
  1270. {
  1271. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1272. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1273. }
  1274. // Verify that the return type is a handle to the type
  1275. if( func.returnType != asCDataType::CreateObjectHandle(objectType, false) )
  1276. return ConfigError(asINVALID_DECLARATION);
  1277. // Implicit factories must take one and only one parameter
  1278. /* if( behaviour == asBEHAVE_IMPLICIT_FACTORY &&
  1279. func.parameterTypes.GetLength() != 1 )
  1280. return ConfigError(asINVALID_DECLARATION);
  1281. */
  1282. // TODO: Verify that the same factory function hasn't been registered already
  1283. // The templates take a hidden parameter with the object type
  1284. if( (objectType->flags & asOBJ_TEMPLATE) &&
  1285. (func.parameterTypes.GetLength() == 0 ||
  1286. !func.parameterTypes[0].IsReference()) )
  1287. {
  1288. return ConfigError(asINVALID_DECLARATION);
  1289. }
  1290. // Store all factory functions in a list
  1291. if( (func.parameterTypes.GetLength() == 0) ||
  1292. (func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) )
  1293. {
  1294. func.id = beh->factory = AddBehaviourFunction(func, internal);
  1295. beh->factories.PushLast(beh->factory);
  1296. }
  1297. else
  1298. {
  1299. func.id = AddBehaviourFunction(func, internal);
  1300. beh->factories.PushLast(func.id);
  1301. /*
  1302. if( behaviour == asBEHAVE_IMPLICIT_FACTORY )
  1303. {
  1304. beh->operators.PushLast(behaviour);
  1305. beh->operators.PushLast(func.id);
  1306. }
  1307. */ }
  1308. }
  1309. else if( behaviour == asBEHAVE_ADDREF )
  1310. {
  1311. // Must be a ref type and must not have asOBJ_NOHANDLE, nor asOBJ_SCOPED
  1312. if( !(func.objectType->flags & asOBJ_REF) ||
  1313. (func.objectType->flags & asOBJ_NOHANDLE) ||
  1314. (func.objectType->flags & asOBJ_SCOPED) )
  1315. {
  1316. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1317. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1318. }
  1319. if( beh->addref )
  1320. return ConfigError(asALREADY_REGISTERED);
  1321. // Verify that the return type is void
  1322. if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  1323. return ConfigError(asINVALID_DECLARATION);
  1324. // Verify that there are no parameters
  1325. if( func.parameterTypes.GetLength() > 0 )
  1326. return ConfigError(asINVALID_DECLARATION);
  1327. func.id = beh->addref = AddBehaviourFunction(func, internal);
  1328. }
  1329. else if( behaviour == asBEHAVE_RELEASE )
  1330. {
  1331. // Must be a ref type and must not have asOBJ_NOHANDLE
  1332. if( !(func.objectType->flags & asOBJ_REF) || (func.objectType->flags & asOBJ_NOHANDLE) )
  1333. {
  1334. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1335. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1336. }
  1337. if( beh->release )
  1338. return ConfigError(asALREADY_REGISTERED);
  1339. // Verify that the return type is void
  1340. if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  1341. return ConfigError(asINVALID_DECLARATION);
  1342. // Verify that there are no parameters
  1343. if( func.parameterTypes.GetLength() > 0 )
  1344. return ConfigError(asINVALID_DECLARATION);
  1345. func.id = beh->release = AddBehaviourFunction(func, internal);
  1346. }
  1347. else if( behaviour == asBEHAVE_TEMPLATE_CALLBACK )
  1348. {
  1349. // Must be a template type
  1350. if( !(func.objectType->flags & asOBJ_TEMPLATE) )
  1351. {
  1352. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1353. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1354. }
  1355. if( beh->templateCallback )
  1356. return ConfigError(asALREADY_REGISTERED);
  1357. // Verify that the return type is bool
  1358. if( func.returnType != asCDataType::CreatePrimitive(ttBool, false) )
  1359. return ConfigError(asINVALID_DECLARATION);
  1360. // Verify that there is one parameters
  1361. if( func.parameterTypes.GetLength() != 1 )
  1362. return ConfigError(asINVALID_DECLARATION);
  1363. func.id = beh->templateCallback = AddBehaviourFunction(func, internal);
  1364. }
  1365. else if( behaviour == asBEHAVE_INDEX )
  1366. {
  1367. // Verify that the var type is not used
  1368. if( VerifyVarTypeNotInFunction(&func) < 0 )
  1369. return ConfigError(asINVALID_DECLARATION);
  1370. // Verify that there is only one parameter
  1371. if( func.parameterTypes.GetLength() != 1 )
  1372. return ConfigError(asINVALID_DECLARATION);
  1373. // Verify that the return type is not void
  1374. if( func.returnType.GetTokenType() == ttVoid )
  1375. return ConfigError(asINVALID_DECLARATION);
  1376. // TODO: Verify that the operator hasn't been registered already
  1377. beh->operators.PushLast(behaviour);
  1378. func.id = AddBehaviourFunction(func, internal);
  1379. beh->operators.PushLast(func.id);
  1380. }
  1381. else if( behaviour >= asBEHAVE_FIRST_GC &&
  1382. behaviour <= asBEHAVE_LAST_GC )
  1383. {
  1384. // Only allow GC behaviours for types registered to be garbage collected
  1385. if( !(func.objectType->flags & asOBJ_GC) )
  1386. {
  1387. WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE);
  1388. return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE);
  1389. }
  1390. // Verify parameter count
  1391. if( (behaviour == asBEHAVE_GETREFCOUNT ||
  1392. behaviour == asBEHAVE_SETGCFLAG ||
  1393. behaviour == asBEHAVE_GETGCFLAG) &&
  1394. func.parameterTypes.GetLength() != 0 )
  1395. return ConfigError(asINVALID_DECLARATION);
  1396. if( (behaviour == asBEHAVE_ENUMREFS ||
  1397. behaviour == asBEHAVE_RELEASEREFS) &&
  1398. func.parameterTypes.GetLength() != 1 )
  1399. return ConfigError(asINVALID_DECLARATION);
  1400. // Verify return type
  1401. if( behaviour == asBEHAVE_GETREFCOUNT &&
  1402. func.returnType != asCDataType::CreatePrimitive(ttInt, false) )
  1403. return ConfigError(asINVALID_DECLARATION);
  1404. if( behaviour == asBEHAVE_GETGCFLAG &&
  1405. func.returnType != asCDataType::CreatePrimitive(ttBool, false) )
  1406. return ConfigError(asINVALID_DECLARATION);
  1407. if( (behaviour == asBEHAVE_SETGCFLAG ||
  1408. behaviour == asBEHAVE_ENUMREFS ||
  1409. behaviour == asBEHAVE_RELEASEREFS) &&
  1410. func.returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  1411. return ConfigError(asINVALID_DECLARATION);
  1412. if( behaviour == asBEHAVE_GETREFCOUNT )
  1413. func.id = beh->gcGetRefCount = AddBehaviourFunction(func, internal);
  1414. else if( behaviour == asBEHAVE_SETGCFLAG )
  1415. func.id = beh->gcSetFlag = AddBehaviourFunction(func, internal);
  1416. else if( behaviour == asBEHAVE_GETGCFLAG )
  1417. func.id = beh->gcGetFlag = AddBehaviourFunction(func, internal);
  1418. else if( behaviour == asBEHAVE_ENUMREFS )
  1419. func.id = beh->gcEnumReferences = AddBehaviourFunction(func, internal);
  1420. else if( behaviour == asBEHAVE_RELEASEREFS )
  1421. func.id = beh->gcReleaseAllReferences = AddBehaviourFunction(func, internal);
  1422. }
  1423. else if( behaviour == asBEHAVE_IMPLICIT_VALUE_CAST ||
  1424. behaviour == asBEHAVE_VALUE_CAST )
  1425. {
  1426. // Verify parameter count
  1427. if( func.parameterTypes.GetLength() != 0 )
  1428. return ConfigError(asINVALID_DECLARATION);
  1429. // Verify return type
  1430. if( func.returnType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, false)) )
  1431. return ConfigError(asNOT_SUPPORTED);
  1432. if( func.returnType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  1433. return ConfigError(asINVALID_DECLARATION);
  1434. // TODO: verify that the same cast is not registered already (const or non-const is treated the same for the return type)
  1435. beh->operators.PushLast(behaviour);
  1436. func.id = AddBehaviourFunction(func, internal);
  1437. beh->operators.PushLast(func.id);
  1438. }
  1439. else if( behaviour == asBEHAVE_REF_CAST ||
  1440. behaviour == asBEHAVE_IMPLICIT_REF_CAST )
  1441. {
  1442. // Verify parameter count
  1443. if( func.parameterTypes.GetLength() != 0 )
  1444. return ConfigError(asINVALID_DECLARATION);
  1445. // Verify return type
  1446. if( !func.returnType.IsObjectHandle() )
  1447. return ConfigError(asINVALID_DECLARATION);
  1448. // TODO: verify that the same cast is not registered already (cosnt or non-const is treated the same for the return type)
  1449. beh->operators.PushLast(behaviour);
  1450. func.id = AddBehaviourFunction(func, internal);
  1451. beh->operators.PushLast(func.id);
  1452. }
  1453. else
  1454. {
  1455. asASSERT(false);
  1456. return ConfigError(asINVALID_ARG);
  1457. }
  1458. // Return function id as success
  1459. return func.id;
  1460. }
  1461. int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func)
  1462. {
  1463. // Don't allow var type in this function
  1464. if( func->returnType.GetTokenType() == ttQuestion )
  1465. return asINVALID_DECLARATION;
  1466. for( unsigned int n = 0; n < func->parameterTypes.GetLength(); n++ )
  1467. if( func->parameterTypes[n].GetTokenType() == ttQuestion )
  1468. return asINVALID_DECLARATION;
  1469. return 0;
  1470. }
  1471. int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal)
  1472. {
  1473. asUINT n;
  1474. int id = GetNextScriptFunctionId();
  1475. asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface);
  1476. newInterface->func = internal.func;
  1477. newInterface->baseOffset = internal.baseOffset;
  1478. newInterface->callConv = internal.callConv;
  1479. newInterface->scriptReturnSize = internal.scriptReturnSize;
  1480. newInterface->hostReturnInMemory = internal.hostReturnInMemory;
  1481. newInterface->hostReturnFloat = internal.hostReturnFloat;
  1482. newInterface->hostReturnSize = internal.hostReturnSize;
  1483. newInterface->paramSize = internal.paramSize;
  1484. newInterface->takesObjByVal = internal.takesObjByVal;
  1485. newInterface->paramAutoHandles = internal.paramAutoHandles;
  1486. newInterface->returnAutoHandle = internal.returnAutoHandle;
  1487. newInterface->hasAutoHandles = internal.hasAutoHandles;
  1488. asCScriptFunction *f = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
  1489. asASSERT(func.name != "" && func.name != "f");
  1490. f->name = func.name;
  1491. f->sysFuncIntf = newInterface;
  1492. f->returnType = func.returnType;
  1493. f->objectType = func.objectType;
  1494. f->id = id;
  1495. f->isReadOnly = func.isReadOnly;
  1496. for( n = 0; n < func.parameterTypes.GetLength(); n++ )
  1497. {
  1498. f->parameterTypes.PushLast(func.parameterTypes[n]);
  1499. f->inOutFlags.PushLast(func.inOutFlags[n]);
  1500. }
  1501. SetScriptFunction(f);
  1502. // If parameter type from other groups are used, add references
  1503. if( f->returnType.GetObjectType() )
  1504. {
  1505. asCConfigGroup *group = FindConfigGroupForObjectType(f->returnType.GetObjectType());
  1506. currentGroup->RefConfigGroup(group);
  1507. }
  1508. for( n = 0; n < f->parameterTypes.GetLength(); n++ )
  1509. {
  1510. if( f->parameterTypes[n].GetObjectType() )
  1511. {
  1512. asCConfigGroup *group = FindConfigGroupForObjectType(f->parameterTypes[n].GetObjectType());
  1513. currentGroup->RefConfigGroup(group);
  1514. }
  1515. }
  1516. return id;
  1517. }
  1518. // interface
  1519. int asCScriptEngine::RegisterGlobalProperty(const char *declaration, void *pointer)
  1520. {
  1521. asCDataType type;
  1522. asCString name;
  1523. int r;
  1524. asCBuilder bld(this, 0);
  1525. if( (r = bld.VerifyProperty(0, declaration, name, type)) < 0 )
  1526. return ConfigError(r);
  1527. // Don't allow registering references as global properties
  1528. if( type.IsReference() )
  1529. return ConfigError(asINVALID_TYPE);
  1530. // Store the property info
  1531. asCGlobalProperty *prop = AllocateGlobalProperty();
  1532. prop->name = name;
  1533. prop->type = type;
  1534. prop->SetRegisteredAddress(pointer);
  1535. registeredGlobalProps.PushLast(prop);
  1536. currentGroup->globalProps.PushLast(prop);
  1537. // If from another group add reference
  1538. if( type.GetObjectType() )
  1539. {
  1540. asCConfigGroup *group = FindConfigGroupForObjectType(type.GetObjectType());
  1541. currentGroup->RefConfigGroup(group);
  1542. }
  1543. return asSUCCESS;
  1544. }
  1545. // internal
  1546. asCGlobalProperty *asCScriptEngine::AllocateGlobalProperty()
  1547. {
  1548. asCGlobalProperty *prop = asNEW(asCGlobalProperty);
  1549. // First check the availability of a free slot
  1550. if( freeGlobalPropertyIds.GetLength() )
  1551. {
  1552. prop->id = freeGlobalPropertyIds.PopLast();
  1553. globalProperties[prop->id] = prop;
  1554. return prop;
  1555. }
  1556. prop->id = (asUINT)globalProperties.GetLength();
  1557. globalProperties.PushLast(prop);
  1558. return prop;
  1559. }
  1560. // internal
  1561. void asCScriptEngine::FreeUnusedGlobalProperties()
  1562. {
  1563. for( asUINT n = 0; n < globalProperties.GetLength(); n++ )
  1564. {
  1565. if( globalProperties[n] && globalProperties[n]->refCount.get() == 0 )
  1566. {
  1567. freeGlobalPropertyIds.PushLast(n);
  1568. asDELETE(globalProperties[n], asCGlobalProperty);
  1569. globalProperties[n] = 0;
  1570. }
  1571. }
  1572. }
  1573. // interface
  1574. int asCScriptEngine::GetGlobalPropertyCount()
  1575. {
  1576. return (int)registeredGlobalProps.GetLength();
  1577. }
  1578. // interface
  1579. // TODO: If the typeId ever encodes the const flag, then the isConst parameter should be removed
  1580. int asCScriptEngine::GetGlobalPropertyByIndex(asUINT index, const char **name, int *typeId, bool *isConst, const char **configGroup, void **pointer)
  1581. {
  1582. if( index >= registeredGlobalProps.GetLength() )
  1583. return asINVALID_ARG;
  1584. if( name )
  1585. *name = registeredGlobalProps[index]->name.AddressOf();
  1586. if( configGroup )
  1587. {
  1588. asCConfigGroup *group = FindConfigGroupForGlobalVar(index);
  1589. if( group )
  1590. *configGroup = group->groupName.AddressOf();
  1591. else
  1592. *configGroup = 0;
  1593. }
  1594. if( typeId )
  1595. *typeId = GetTypeIdFromDataType(registeredGlobalProps[index]->type);
  1596. if( isConst )
  1597. *isConst = registeredGlobalProps[index]->type.IsReadOnly();
  1598. if( pointer )
  1599. *pointer = registeredGlobalProps[index]->realAddress;
  1600. return asSUCCESS;
  1601. }
  1602. // interface
  1603. int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv)
  1604. {
  1605. if( obj == 0 )
  1606. return ConfigError(asINVALID_ARG);
  1607. // Determine the object type
  1608. asCDataType dt;
  1609. asCBuilder bld(this, 0);
  1610. int r = bld.ParseDataType(obj, &dt);
  1611. if( r < 0 )
  1612. return ConfigError(r);
  1613. if( dt.GetObjectType() == 0 )
  1614. return ConfigError(asINVALID_ARG);
  1615. return RegisterMethodToObjectType(dt.GetObjectType(), declaration, funcPointer, callConv);
  1616. }
  1617. // internal
  1618. int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv)
  1619. {
  1620. asSSystemFunctionInterface internal;
  1621. int r = DetectCallingConvention(true, funcPointer, callConv, &internal);
  1622. if( r < 0 )
  1623. return ConfigError(r);
  1624. // We only support these calling conventions for object methods
  1625. #ifdef AS_MAX_PORTABILITY
  1626. if( callConv != asCALL_GENERIC )
  1627. return ConfigError(asNOT_SUPPORTED);
  1628. #else
  1629. if( callConv != asCALL_THISCALL &&
  1630. callConv != asCALL_CDECL_OBJLAST &&
  1631. callConv != asCALL_CDECL_OBJFIRST &&
  1632. callConv != asCALL_GENERIC )
  1633. return ConfigError(asNOT_SUPPORTED);
  1634. #endif
  1635. isPrepared = false;
  1636. // Put the system function in the list of system functions
  1637. asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
  1638. asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
  1639. func->sysFuncIntf = newInterface;
  1640. func->objectType = objectType;
  1641. asCBuilder bld(this, 0);
  1642. r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle);
  1643. if( r < 0 )
  1644. {
  1645. // Set as dummy function before deleting
  1646. func->funcType = -1;
  1647. asDELETE(func,asCScriptFunction);
  1648. return ConfigError(asINVALID_DECLARATION);
  1649. }
  1650. // Check name conflicts
  1651. asCDataType x = asCDataType::CreateObject(objectType, false);
  1652. r = bld.CheckNameConflictMember(x, func->name.AddressOf(), 0, 0);
  1653. if( r < 0 )
  1654. {
  1655. asDELETE(func,asCScriptFunction);
  1656. return ConfigError(asNAME_TAKEN);
  1657. }
  1658. func->id = GetNextScriptFunctionId();
  1659. func->objectType->methods.PushLast(func->id);
  1660. SetScriptFunction(func);
  1661. // TODO: This code is repeated in many places
  1662. // If parameter type from other groups are used, add references
  1663. if( func->returnType.GetObjectType() )
  1664. {
  1665. asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType());
  1666. currentGroup->RefConfigGroup(group);
  1667. }
  1668. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  1669. {
  1670. if( func->parameterTypes[n].GetObjectType() )
  1671. {
  1672. asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType());
  1673. currentGroup->RefConfigGroup(group);
  1674. }
  1675. }
  1676. // Check if the method restricts that use of the template to value types or reference types
  1677. if( func->objectType->flags & asOBJ_TEMPLATE )
  1678. {
  1679. if( func->returnType.GetObjectType() == func->objectType->templateSubType.GetObjectType() )
  1680. {
  1681. if( func->returnType.IsObjectHandle() )
  1682. func->objectType->acceptValueSubType = false;
  1683. else if( !func->returnType.IsReference() )
  1684. func->objectType->acceptRefSubType = false;
  1685. }
  1686. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  1687. {
  1688. if( func->parameterTypes[n].GetObjectType() == func->objectType->templateSubType.GetObjectType() )
  1689. {
  1690. // TODO: If unsafe references are allowed, then inout references allow value types
  1691. if( func->parameterTypes[n].IsObjectHandle() || (func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF) )
  1692. func->objectType->acceptValueSubType = false;
  1693. else if( !func->parameterTypes[n].IsReference() )
  1694. func->objectType->acceptRefSubType = false;
  1695. }
  1696. }
  1697. }
  1698. // TODO: beh.copy member will be removed, so this is not necessary
  1699. // Is this the default copy behaviour?
  1700. if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && func->isReadOnly == false &&
  1701. (objectType->flags & asOBJ_SCRIPT_OBJECT || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateObject(func->objectType, false))) )
  1702. {
  1703. func->objectType->beh.copy = func->id;
  1704. func->AddRef();
  1705. }
  1706. // Return the function id as success
  1707. return func->id;
  1708. }
  1709. // interface
  1710. int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv)
  1711. {
  1712. asSSystemFunctionInterface internal;
  1713. int r = DetectCallingConvention(false, funcPointer, callConv, &internal);
  1714. if( r < 0 )
  1715. return ConfigError(r);
  1716. #ifdef AS_MAX_PORTABILITY
  1717. if( callConv != asCALL_GENERIC )
  1718. return ConfigError(asNOT_SUPPORTED);
  1719. #else
  1720. if( callConv != asCALL_CDECL &&
  1721. callConv != asCALL_STDCALL &&
  1722. callConv != asCALL_GENERIC )
  1723. return ConfigError(asNOT_SUPPORTED);
  1724. #endif
  1725. isPrepared = false;
  1726. // Put the system function in the list of system functions
  1727. asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
  1728. asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
  1729. func->sysFuncIntf = newInterface;
  1730. asCBuilder bld(this, 0);
  1731. r = bld.ParseFunctionDeclaration(0, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle);
  1732. if( r < 0 )
  1733. {
  1734. // Set as dummy function before deleting
  1735. func->funcType = -1;
  1736. asDELETE(func,asCScriptFunction);
  1737. return ConfigError(asINVALID_DECLARATION);
  1738. }
  1739. // Check name conflicts
  1740. r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0);
  1741. if( r < 0 )
  1742. {
  1743. asDELETE(func,asCScriptFunction);
  1744. return ConfigError(asNAME_TAKEN);
  1745. }
  1746. func->id = GetNextScriptFunctionId();
  1747. SetScriptFunction(func);
  1748. currentGroup->scriptFunctions.PushLast(func);
  1749. registeredGlobalFuncs.PushLast(func);
  1750. // If parameter type from other groups are used, add references
  1751. if( func->returnType.GetObjectType() )
  1752. {
  1753. asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType());
  1754. currentGroup->RefConfigGroup(group);
  1755. }
  1756. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  1757. {
  1758. if( func->parameterTypes[n].GetObjectType() )
  1759. {
  1760. asCConfigGroup *group = FindConfigGroupForObjectType(func->parameterTypes[n].GetObjectType());
  1761. currentGroup->RefConfigGroup(group);
  1762. }
  1763. }
  1764. // Return the function id as success
  1765. return func->id;
  1766. }
  1767. // interface
  1768. int asCScriptEngine::GetGlobalFunctionCount()
  1769. {
  1770. return (int)registeredGlobalFuncs.GetLength();
  1771. }
  1772. // interface
  1773. int asCScriptEngine::GetGlobalFunctionIdByIndex(asUINT index)
  1774. {
  1775. if( index >= registeredGlobalFuncs.GetLength() )
  1776. return asINVALID_ARG;
  1777. return registeredGlobalFuncs[index]->id;
  1778. }
  1779. asCObjectType *asCScriptEngine::GetObjectType(const char *type)
  1780. {
  1781. // TODO: optimize: Improve linear search
  1782. for( asUINT n = 0; n < objectTypes.GetLength(); n++ )
  1783. if( objectTypes[n] &&
  1784. objectTypes[n]->name == type ) // TODO: template: Should we check the subtype in case of template instances?
  1785. return objectTypes[n];
  1786. return 0;
  1787. }
  1788. void asCScriptEngine::PrepareEngine()
  1789. {
  1790. if( isPrepared ) return;
  1791. if( configFailed ) return;
  1792. asUINT n;
  1793. for( n = 0; n < scriptFunctions.GetLength(); n++ )
  1794. {
  1795. // Determine the host application interface
  1796. if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SYSTEM )
  1797. {
  1798. if( scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_FUNC ||
  1799. scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_METHOD )
  1800. PrepareSystemFunctionGeneric(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this);
  1801. else
  1802. PrepareSystemFunction(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this);
  1803. }
  1804. }
  1805. // Validate object type registrations
  1806. for( n = 0; n < objectTypes.GetLength(); n++ )
  1807. {
  1808. if( objectTypes[n] && !(objectTypes[n]->flags & asOBJ_SCRIPT_OBJECT) )
  1809. {
  1810. bool missingBehaviour = false;
  1811. const char *infoMsg = 0;
  1812. // Verify that GC types have all behaviours
  1813. if( objectTypes[n]->flags & asOBJ_GC )
  1814. {
  1815. if( objectTypes[n]->beh.addref == 0 ||
  1816. objectTypes[n]->beh.release == 0 ||
  1817. objectTypes[n]->beh.gcGetRefCount == 0 ||
  1818. objectTypes[n]->beh.gcSetFlag == 0 ||
  1819. objectTypes[n]->beh.gcGetFlag == 0 ||
  1820. objectTypes[n]->beh.gcEnumReferences == 0 ||
  1821. objectTypes[n]->beh.gcReleaseAllReferences == 0 )
  1822. {
  1823. infoMsg = TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR;
  1824. missingBehaviour = true;
  1825. }
  1826. }
  1827. // Verify that scoped ref types have the release behaviour
  1828. else if( objectTypes[n]->flags & asOBJ_SCOPED )
  1829. {
  1830. if( objectTypes[n]->beh.release == 0 )
  1831. {
  1832. infoMsg = TXT_SCOPE_REQUIRE_REL_BEHAVIOUR;
  1833. missingBehaviour = true;
  1834. }
  1835. }
  1836. // Verify that ref types have add ref and release behaviours
  1837. else if( (objectTypes[n]->flags & asOBJ_REF) &&
  1838. !(objectTypes[n]->flags & asOBJ_NOHANDLE) )
  1839. {
  1840. if( objectTypes[n]->beh.addref == 0 ||
  1841. objectTypes[n]->beh.release == 0 )
  1842. {
  1843. infoMsg = TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR;
  1844. missingBehaviour = true;
  1845. }
  1846. }
  1847. // Verify that non-pod value types have the constructor and destructor registered
  1848. else if( (objectTypes[n]->flags & asOBJ_VALUE) &&
  1849. !(objectTypes[n]->flags & asOBJ_POD) )
  1850. {
  1851. if( objectTypes[n]->beh.construct == 0 ||
  1852. objectTypes[n]->beh.destruct == 0 )
  1853. {
  1854. infoMsg = TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR;
  1855. missingBehaviour = true;
  1856. }
  1857. }
  1858. if( missingBehaviour )
  1859. {
  1860. asCString str;
  1861. str.Format(TXT_TYPE_s_IS_MISSING_BEHAVIOURS, objectTypes[n]->name.AddressOf());
  1862. WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  1863. WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, infoMsg);
  1864. ConfigError(asINVALID_CONFIGURATION);
  1865. }
  1866. }
  1867. }
  1868. isPrepared = true;
  1869. }
  1870. int asCScriptEngine::ConfigError(int err)
  1871. {
  1872. configFailed = true;
  1873. return err;
  1874. }
  1875. // interface
  1876. int asCScriptEngine::RegisterStringFactory(const char *datatype, const asSFuncPtr &funcPointer, asDWORD callConv)
  1877. {
  1878. asSSystemFunctionInterface internal;
  1879. int r = DetectCallingConvention(false, funcPointer, callConv, &internal);
  1880. if( r < 0 )
  1881. return ConfigError(r);
  1882. #ifdef AS_MAX_PORTABILITY
  1883. if( callConv != asCALL_GENERIC )
  1884. return ConfigError(asNOT_SUPPORTED);
  1885. #else
  1886. if( callConv != asCALL_CDECL &&
  1887. callConv != asCALL_STDCALL &&
  1888. callConv != asCALL_GENERIC )
  1889. return ConfigError(asNOT_SUPPORTED);
  1890. #endif
  1891. // Put the system function in the list of system functions
  1892. asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal);
  1893. asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM);
  1894. func->name = "_string_factory_";
  1895. func->sysFuncIntf = newInterface;
  1896. asCBuilder bld(this, 0);
  1897. asCDataType dt;
  1898. r = bld.ParseDataType(datatype, &dt);
  1899. if( r < 0 )
  1900. {
  1901. // Set as dummy before deleting
  1902. func->funcType = -1;
  1903. asDELETE(func,asCScriptFunction);
  1904. return ConfigError(asINVALID_TYPE);
  1905. }
  1906. func->returnType = dt;
  1907. func->parameterTypes.PushLast(asCDataType::CreatePrimitive(ttInt, true));
  1908. asCDataType parm1 = asCDataType::CreatePrimitive(ttUInt8, true);
  1909. parm1.MakeReference(true);
  1910. func->parameterTypes.PushLast(parm1);
  1911. func->id = GetNextScriptFunctionId();
  1912. SetScriptFunction(func);
  1913. stringFactory = func;
  1914. if( func->returnType.GetObjectType() )
  1915. {
  1916. asCConfigGroup *group = FindConfigGroupForObjectType(func->returnType.GetObjectType());
  1917. if( group == 0 ) group = &defaultGroup;
  1918. group->scriptFunctions.PushLast(func);
  1919. }
  1920. // Register function id as success
  1921. return func->id;
  1922. }
  1923. // interface
  1924. int asCScriptEngine::GetStringFactoryReturnTypeId()
  1925. {
  1926. if( stringFactory == 0 )
  1927. return asNO_FUNCTION;
  1928. return GetTypeIdFromDataType(stringFactory->returnType);
  1929. }
  1930. // interface
  1931. asCModule *asCScriptEngine::GetModule(const char *_name, bool create)
  1932. {
  1933. // Accept null as well as zero-length string
  1934. const char *name = "";
  1935. if( _name != 0 ) name = _name;
  1936. if( lastModule && lastModule->name == name )
  1937. return lastModule;
  1938. // TODO: optimize: Improve linear search
  1939. for( asUINT n = 0; n < scriptModules.GetLength(); ++n )
  1940. if( scriptModules[n] && scriptModules[n]->name == name )
  1941. {
  1942. lastModule = scriptModules[n];
  1943. return lastModule;
  1944. }
  1945. if( create )
  1946. {
  1947. asCModule *module = asNEW(asCModule)(name, this);
  1948. scriptModules.PushLast(module);
  1949. lastModule = module;
  1950. return lastModule;
  1951. }
  1952. return 0;
  1953. }
  1954. asCModule *asCScriptEngine::GetModuleFromFuncId(int id)
  1955. {
  1956. if( id < 0 ) return 0;
  1957. if( id >= (int)scriptFunctions.GetLength() ) return 0;
  1958. asCScriptFunction *func = scriptFunctions[id];
  1959. if( func == 0 ) return 0;
  1960. return func->module;
  1961. }
  1962. // internal
  1963. int asCScriptEngine::RequestBuild()
  1964. {
  1965. ENTERCRITICALSECTION(engineCritical);
  1966. if( isBuilding )
  1967. {
  1968. LEAVECRITICALSECTION(engineCritical);
  1969. return asBUILD_IN_PROGRESS;
  1970. }
  1971. isBuilding = true;
  1972. LEAVECRITICALSECTION(engineCritical);
  1973. return 0;
  1974. }
  1975. // internal
  1976. void asCScriptEngine::BuildCompleted()
  1977. {
  1978. // Always free up pooled memory after a completed build
  1979. memoryMgr.FreeUnusedMemory();
  1980. isBuilding = false;
  1981. }
  1982. #ifdef AS_DEPRECATED
  1983. // Deprecated since 2009-12-08, 2.18.0
  1984. // interface
  1985. int asCScriptEngine::ExecuteString(const char *module, const char *script, asIScriptContext **ctx, asDWORD flags)
  1986. {
  1987. int r;
  1988. if( (r = RequestBuild()) < 0 )
  1989. return r;
  1990. PrepareEngine();
  1991. // Make sure the config worked
  1992. if( configFailed )
  1993. {
  1994. if( ctx && !(flags & asEXECSTRING_USE_MY_CONTEXT) )
  1995. *ctx = 0;
  1996. WriteMessage("",0,0,asMSGTYPE_ERROR,TXT_INVALID_CONFIGURATION);
  1997. isBuilding = false;
  1998. return asINVALID_CONFIGURATION;
  1999. }
  2000. asIScriptContext *exec = 0;
  2001. if( !(flags & asEXECSTRING_USE_MY_CONTEXT) )
  2002. {
  2003. int r = CreateContext(&exec, false);
  2004. if( r < 0 )
  2005. {
  2006. if( ctx && !(flags & asEXECSTRING_USE_MY_CONTEXT) )
  2007. *ctx = 0;
  2008. isBuilding = false;
  2009. return r;
  2010. }
  2011. if( ctx )
  2012. {
  2013. *ctx = exec;
  2014. exec->AddRef();
  2015. }
  2016. }
  2017. else
  2018. {
  2019. if( *ctx == 0 )
  2020. {
  2021. isBuilding = false;
  2022. return asINVALID_ARG;
  2023. }
  2024. exec = *ctx;
  2025. exec->AddRef();
  2026. }
  2027. // Make sure the context isn't holding a reference to the previous ExecuteString function()
  2028. exec->Unprepare();
  2029. // Get the module to compile the string in
  2030. asCModule *mod = GetModule(module, true);
  2031. // Compile string function
  2032. asCBuilder builder(this, mod);
  2033. asCString str = script;
  2034. str = "void ExecuteString(){\n" + str + "\n;}";
  2035. r = builder.BuildString(str.AddressOf(), (asCContext*)exec);
  2036. BuildCompleted();
  2037. if( r < 0 )
  2038. {
  2039. if( ctx && !(flags & asEXECSTRING_USE_MY_CONTEXT) )
  2040. {
  2041. (*ctx)->Release();
  2042. *ctx = 0;
  2043. }
  2044. exec->Release();
  2045. return asERROR;
  2046. }
  2047. // Prepare and execute the context
  2048. r = ((asCContext*)exec)->Prepare(((asCContext*)exec)->stringFunction->id);
  2049. if( r < 0 )
  2050. {
  2051. if( ctx && !(flags & asEXECSTRING_USE_MY_CONTEXT) )
  2052. {
  2053. (*ctx)->Release();
  2054. *ctx = 0;
  2055. }
  2056. exec->Release();
  2057. return r;
  2058. }
  2059. if( flags & asEXECSTRING_ONLY_PREPARE )
  2060. r = asEXECUTION_PREPARED;
  2061. else
  2062. r = exec->Execute();
  2063. exec->Release();
  2064. return r;
  2065. }
  2066. #endif
  2067. void asCScriptEngine::RemoveTemplateInstanceType(asCObjectType *t)
  2068. {
  2069. int n;
  2070. // Destroy the factory stubs
  2071. for( n = 0; n < (int)t->beh.factories.GetLength(); n++ )
  2072. {
  2073. // Make sure the factory stub isn't referencing this object anymore
  2074. scriptFunctions[t->beh.factories[n]]->ReleaseAllHandles(this);
  2075. scriptFunctions[t->beh.factories[n]]->Release();
  2076. }
  2077. t->beh.factories.SetLength(0);
  2078. // Destroy the specialized functions
  2079. for( n = 1; n < (int)t->beh.operators.GetLength(); n += 2 )
  2080. {
  2081. if( t->beh.operators[n] && scriptFunctions[t->beh.operators[n]]->objectType == t )
  2082. {
  2083. scriptFunctions[t->beh.operators[n]]->Release();
  2084. }
  2085. }
  2086. t->beh.operators.SetLength(0);
  2087. // Start searching from the end of the list, as most of
  2088. // the time it will be the last two types
  2089. for( n = (int)templateTypes.GetLength()-1; n >= 0; n-- )
  2090. {
  2091. if( templateTypes[n] == t )
  2092. {
  2093. if( n == (signed)templateTypes.GetLength()-1 )
  2094. templateTypes.PopLast();
  2095. else
  2096. templateTypes[n] = templateTypes.PopLast();
  2097. }
  2098. }
  2099. for( n = (int)templateInstanceTypes.GetLength()-1; n >= 0; n-- )
  2100. {
  2101. if( templateInstanceTypes[n] == t )
  2102. {
  2103. if( n == (signed)templateInstanceTypes.GetLength()-1 )
  2104. templateInstanceTypes.PopLast();
  2105. else
  2106. templateInstanceTypes[n] = templateInstanceTypes.PopLast();
  2107. }
  2108. }
  2109. asDELETE(t,asCObjectType);
  2110. }
  2111. asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateType, asCDataType &subType)
  2112. {
  2113. asUINT n;
  2114. // Is there any template instance type or template specialization already with this subtype?
  2115. for( n = 0; n < templateTypes.GetLength(); n++ )
  2116. {
  2117. if( templateTypes[n] &&
  2118. templateTypes[n]->name == templateType->name &&
  2119. templateTypes[n]->templateSubType == subType )
  2120. return templateTypes[n];
  2121. }
  2122. // No previous template instance exists
  2123. // Make sure this template supports the subtype
  2124. if( !templateType->acceptValueSubType && (subType.IsPrimitive() || (subType.GetObjectType()->flags & asOBJ_VALUE)) )
  2125. return 0;
  2126. if( !templateType->acceptRefSubType && (subType.IsObject() && (subType.GetObjectType()->flags & asOBJ_REF)) )
  2127. return 0;
  2128. // Create a new template instance type based on the templateType
  2129. asCObjectType *ot = asNEW(asCObjectType)(this);
  2130. ot->templateSubType = subType;
  2131. ot->flags = templateType->flags;
  2132. ot->size = templateType->size;
  2133. ot->name = templateType->name;
  2134. // Before filling in the methods, call the template instance callback behaviour to validate the type
  2135. if( templateType->beh.templateCallback )
  2136. {
  2137. asCScriptFunction *callback = scriptFunctions[templateType->beh.templateCallback];
  2138. if( !CallGlobalFunctionRetBool(ot, 0, callback->sysFuncIntf, callback) )
  2139. {
  2140. // The type cannot be instanciated
  2141. ot->templateSubType = asCDataType();
  2142. asDELETE(ot, asCObjectType);
  2143. return 0;
  2144. }
  2145. }
  2146. ot->methods = templateType->methods;
  2147. for( n = 0; n < ot->methods.GetLength(); n++ )
  2148. scriptFunctions[ot->methods[n]]->AddRef();
  2149. // Store the real factory in the constructor
  2150. ot->beh.construct = templateType->beh.factory;
  2151. ot->beh.constructors = templateType->beh.factories;
  2152. for( n = 0; n < ot->beh.constructors.GetLength(); n++ )
  2153. scriptFunctions[ot->beh.constructors[n]]->AddRef();
  2154. // Generate factory stubs for each of the factories
  2155. for( n = 0; n < templateType->beh.factories.GetLength(); n++ )
  2156. {
  2157. int factoryId = templateType->beh.factories[n];
  2158. asCScriptFunction *factory = scriptFunctions[factoryId];
  2159. asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SCRIPT);
  2160. func->name = "factstub";
  2161. func->id = GetNextScriptFunctionId();
  2162. func->returnType = asCDataType::CreateObjectHandle(ot, false);
  2163. // Skip the first parameter as this is the object type pointer that the stub will add
  2164. for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ )
  2165. {
  2166. func->parameterTypes.PushLast(factory->parameterTypes[p]);
  2167. func->inOutFlags.PushLast(factory->inOutFlags[p]);
  2168. }
  2169. SetScriptFunction(func);
  2170. asCBuilder builder(this, 0);
  2171. asCCompiler compiler(this);
  2172. compiler.CompileTemplateFactoryStub(&builder, factoryId, ot, func);
  2173. // The function's refCount was already initialized to 1
  2174. ot->beh.factories.PushLast(func->id);
  2175. }
  2176. if( ot->beh.factories.GetLength() )
  2177. ot->beh.factory = ot->beh.factories[0];
  2178. else
  2179. {
  2180. asASSERT(false);
  2181. ot->beh.factory = templateType->beh.factory;
  2182. }
  2183. ot->beh.addref = templateType->beh.addref;
  2184. if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRef();
  2185. ot->beh.release = templateType->beh.release;
  2186. if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRef();
  2187. ot->beh.copy = templateType->beh.copy;
  2188. if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRef();
  2189. ot->beh.operators = templateType->beh.operators;
  2190. for( n = 1; n < ot->beh.operators.GetLength(); n += 2 )
  2191. {
  2192. scriptFunctions[ot->beh.operators[n]]->AddRef();
  2193. }
  2194. ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount;
  2195. if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRef();
  2196. ot->beh.gcSetFlag = templateType->beh.gcSetFlag;
  2197. if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRef();
  2198. ot->beh.gcGetFlag = templateType->beh.gcGetFlag;
  2199. if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRef();
  2200. ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences;
  2201. if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRef();
  2202. ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences;
  2203. if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRef();
  2204. // As the new template type is instanciated, the engine should
  2205. // generate new functions to substitute the ones with the template subtype.
  2206. for( n = 1; n < ot->beh.operators.GetLength(); n += 2 )
  2207. {
  2208. int funcId = ot->beh.operators[n];
  2209. asCScriptFunction *func = scriptFunctions[funcId];
  2210. if( GenerateNewTemplateFunction(templateType, ot, subType, func, &func) )
  2211. {
  2212. // Release the old function, the new one already has its ref count set to 1
  2213. scriptFunctions[ot->beh.operators[n]]->Release();
  2214. ot->beh.operators[n] = func->id;
  2215. }
  2216. }
  2217. // As the new template type is instanciated, the engine should
  2218. // generate new functions to substitute the ones with the template subtype.
  2219. for( n = 0; n < ot->methods.GetLength(); n++ )
  2220. {
  2221. int funcId = ot->methods[n];
  2222. asCScriptFunction *func = scriptFunctions[funcId];
  2223. if( GenerateNewTemplateFunction(templateType, ot, subType, func, &func) )
  2224. {
  2225. // Release the old function, the new one already has its ref count set to 1
  2226. scriptFunctions[ot->methods[n]]->Release();
  2227. ot->methods[n] = func->id;
  2228. }
  2229. }
  2230. // Increase ref counter for sub type if it is an object type
  2231. if( ot->templateSubType.GetObjectType() ) ot->templateSubType.GetObjectType()->AddRef();
  2232. // Verify if the subtype contains a garbage collected object, in which case this template is a potential circular reference
  2233. // TODO: We may be a bit smarter here. If we can guarantee that the array type cannot be part of the
  2234. // potential circular reference then we don't need to set the flag
  2235. if( ot->templateSubType.GetObjectType() && (ot->templateSubType.GetObjectType()->flags & asOBJ_GC) )
  2236. ot->flags |= asOBJ_GC;
  2237. else if( ot->name == defaultArrayObjectType->name )
  2238. ot->flags &= ~asOBJ_GC;
  2239. templateTypes.PushLast(ot);
  2240. // We need to store the object type somewhere for clean-up later
  2241. // TODO: Why do we need both templateTypes and templateInstanceTypes? It is possible to differ between template instance and template specialization by checking for the asOBJ_TEMPLATE flag
  2242. templateInstanceTypes.PushLast(ot);
  2243. return ot;
  2244. }
  2245. bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *ot, asCDataType &subType, asCScriptFunction *func, asCScriptFunction **newFunc)
  2246. {
  2247. bool needNewFunc = false;
  2248. if( func->returnType.GetObjectType() == templateType->templateSubType.GetObjectType() ||
  2249. func->returnType.GetObjectType() == templateType )
  2250. needNewFunc = true;
  2251. else
  2252. {
  2253. for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
  2254. {
  2255. if( func->parameterTypes[p].GetObjectType() == templateType->templateSubType.GetObjectType() ||
  2256. func->parameterTypes[p].GetObjectType() == templateType )
  2257. {
  2258. needNewFunc = true;
  2259. break;
  2260. }
  2261. }
  2262. }
  2263. if( needNewFunc )
  2264. {
  2265. asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcType);
  2266. func2->name = func->name;
  2267. func2->id = GetNextScriptFunctionId();
  2268. if( func->returnType.GetObjectType() == templateType->templateSubType.GetObjectType() )
  2269. {
  2270. func2->returnType = subType;
  2271. if( func->returnType.IsObjectHandle() )
  2272. func2->returnType.MakeHandle(true, true);
  2273. func2->returnType.MakeReference(func->returnType.IsReference());
  2274. func2->returnType.MakeReadOnly(func->returnType.IsReadOnly());
  2275. }
  2276. else if( func->returnType.GetObjectType() == templateType )
  2277. {
  2278. if( func2->returnType.IsObjectHandle() )
  2279. func2->returnType = asCDataType::CreateObjectHandle(ot, false);
  2280. else
  2281. func2->returnType = asCDataType::CreateObject(ot, false);
  2282. func2->returnType.MakeReference(func->returnType.IsReference());
  2283. func2->returnType.MakeReadOnly(func->returnType.IsReadOnly());
  2284. }
  2285. else
  2286. func2->returnType = func->returnType;
  2287. func2->parameterTypes.SetLength(func->parameterTypes.GetLength());
  2288. for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ )
  2289. {
  2290. if( func->parameterTypes[p].GetObjectType() == templateType->templateSubType.GetObjectType() )
  2291. {
  2292. func2->parameterTypes[p] = subType;
  2293. if( func->parameterTypes[p].IsObjectHandle() )
  2294. func2->parameterTypes[p].MakeHandle(true);
  2295. func2->parameterTypes[p].MakeReference(func->parameterTypes[p].IsReference());
  2296. func2->parameterTypes[p].MakeReadOnly(func->parameterTypes[p].IsReference());
  2297. }
  2298. else if( func->parameterTypes[p].GetObjectType() == templateType )
  2299. {
  2300. if( func2->parameterTypes[p].IsObjectHandle() )
  2301. func2->parameterTypes[p] = asCDataType::CreateObjectHandle(ot, false);
  2302. else
  2303. func2->parameterTypes[p] = asCDataType::CreateObject(ot, false);
  2304. func2->parameterTypes[p].MakeReference(func->parameterTypes[p].IsReference());
  2305. func2->parameterTypes[p].MakeReadOnly(func->parameterTypes[p].IsReadOnly());
  2306. }
  2307. else
  2308. func2->parameterTypes[p] = func->parameterTypes[p];
  2309. }
  2310. // TODO: template: Must be careful when instanciating templates for garbage collected types
  2311. // If the template hasn't been registered with the behaviours, it shouldn't
  2312. // permit instanciation of garbage collected types that in turn may refer to
  2313. // this instance.
  2314. func2->inOutFlags = func->inOutFlags;
  2315. func2->isReadOnly = func->isReadOnly;
  2316. func2->objectType = ot;
  2317. func2->stackNeeded = func->stackNeeded;
  2318. func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf);
  2319. SetScriptFunction(func2);
  2320. // Return the new function
  2321. *newFunc = func2;
  2322. }
  2323. return needNewFunc;
  2324. }
  2325. void asCScriptEngine::CallObjectMethod(void *obj, int func)
  2326. {
  2327. asCScriptFunction *s = scriptFunctions[func];
  2328. CallObjectMethod(obj, s->sysFuncIntf, s);
  2329. }
  2330. void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s)
  2331. {
  2332. #ifdef __GNUC__
  2333. if( i->callConv == ICC_GENERIC_METHOD )
  2334. {
  2335. asCGeneric gen(this, s, obj, 0);
  2336. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2337. f(&gen);
  2338. }
  2339. else if( i->callConv == ICC_VIRTUAL_THISCALL )
  2340. {
  2341. // For virtual thiscalls we must call the method as a true class method
  2342. // so that the compiler will lookup the function address in the vftable
  2343. union
  2344. {
  2345. asSIMPLEMETHOD_t mthd;
  2346. struct
  2347. {
  2348. asFUNCTION_t func;
  2349. asPWORD baseOffset; // Same size as the pointer
  2350. } f;
  2351. } p;
  2352. p.f.func = (void (*)())(i->func);
  2353. p.f.baseOffset = asPWORD(i->baseOffset);
  2354. void (asCSimpleDummy::*f)() = p.mthd;
  2355. (((asCSimpleDummy*)obj)->*f)();
  2356. }
  2357. else /*if( i->callConv == ICC_THISCALL || i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2358. {
  2359. // Non-virtual thiscall can be called just like any global function, passing the object as the first parameter
  2360. void (*f)(void *) = (void (*)(void *))(i->func);
  2361. f(obj);
  2362. }
  2363. #else
  2364. #ifndef AS_NO_CLASS_METHODS
  2365. if( i->callConv == ICC_THISCALL )
  2366. {
  2367. union
  2368. {
  2369. asSIMPLEMETHOD_t mthd;
  2370. asFUNCTION_t func;
  2371. } p;
  2372. p.func = (void (*)())(i->func);
  2373. void (asCSimpleDummy::*f)() = p.mthd;
  2374. (((asCSimpleDummy*)obj)->*f)();
  2375. }
  2376. else
  2377. #endif
  2378. if( i->callConv == ICC_GENERIC_METHOD )
  2379. {
  2380. asCGeneric gen(this, s, obj, 0);
  2381. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2382. f(&gen);
  2383. }
  2384. else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2385. {
  2386. void (*f)(void *) = (void (*)(void *))(i->func);
  2387. f(obj);
  2388. }
  2389. #endif
  2390. }
  2391. bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func)
  2392. {
  2393. asCScriptFunction *s = scriptFunctions[func];
  2394. asSSystemFunctionInterface *i = s->sysFuncIntf;
  2395. #ifdef __GNUC__
  2396. if( i->callConv == ICC_GENERIC_METHOD )
  2397. {
  2398. asCGeneric gen(this, s, obj, 0);
  2399. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2400. f(&gen);
  2401. return *(bool*)gen.GetReturnPointer();
  2402. }
  2403. else if( i->callConv == ICC_VIRTUAL_THISCALL )
  2404. {
  2405. // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
  2406. union
  2407. {
  2408. asSIMPLEMETHOD_t mthd;
  2409. struct
  2410. {
  2411. asFUNCTION_t func;
  2412. asDWORD baseOffset;
  2413. } f;
  2414. } p;
  2415. p.f.func = (void (*)())(i->func);
  2416. p.f.baseOffset = i->baseOffset;
  2417. bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd);
  2418. return (((asCSimpleDummy*)obj)->*f)();
  2419. }
  2420. else /*if( i->callConv == ICC_THISCALL || i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2421. {
  2422. // Non-virtual thiscall can be called just like any global function, passing the object as the first parameter
  2423. bool (*f)(void *) = (bool (*)(void *))(i->func);
  2424. return f(obj);
  2425. }
  2426. #else
  2427. #ifndef AS_NO_CLASS_METHODS
  2428. if( i->callConv == ICC_THISCALL )
  2429. {
  2430. union
  2431. {
  2432. asSIMPLEMETHOD_t mthd;
  2433. asFUNCTION_t func;
  2434. } p;
  2435. p.func = (void (*)())(i->func);
  2436. bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())p.mthd;
  2437. return (((asCSimpleDummy*)obj)->*f)();
  2438. }
  2439. else
  2440. #endif
  2441. if( i->callConv == ICC_GENERIC_METHOD )
  2442. {
  2443. asCGeneric gen(this, s, obj, 0);
  2444. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2445. f(&gen);
  2446. return *(bool*)gen.GetReturnPointer();
  2447. }
  2448. else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2449. {
  2450. bool (*f)(void *) = (bool (*)(void *))(i->func);
  2451. return f(obj);
  2452. }
  2453. #endif
  2454. }
  2455. int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func)
  2456. {
  2457. asCScriptFunction *s = scriptFunctions[func];
  2458. asSSystemFunctionInterface *i = s->sysFuncIntf;
  2459. #ifdef __GNUC__
  2460. if( i->callConv == ICC_GENERIC_METHOD )
  2461. {
  2462. asCGeneric gen(this, s, obj, 0);
  2463. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2464. f(&gen);
  2465. return *(int*)gen.GetReturnPointer();
  2466. }
  2467. else if( i->callConv == ICC_VIRTUAL_THISCALL )
  2468. {
  2469. // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable
  2470. union
  2471. {
  2472. asSIMPLEMETHOD_t mthd;
  2473. struct
  2474. {
  2475. asFUNCTION_t func;
  2476. asDWORD baseOffset;
  2477. } f;
  2478. } p;
  2479. p.f.func = (void (*)())(i->func);
  2480. p.f.baseOffset = i->baseOffset;
  2481. int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())(p.mthd);
  2482. return (((asCSimpleDummy*)obj)->*f)();
  2483. }
  2484. else /*if( i->callConv == ICC_THISCALL || i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2485. {
  2486. // Non-virtual thiscall can be called just like any global function, passing the object as the first parameter
  2487. int (*f)(void *) = (int (*)(void *))(i->func);
  2488. return f(obj);
  2489. }
  2490. #else
  2491. #ifndef AS_NO_CLASS_METHODS
  2492. if( i->callConv == ICC_THISCALL )
  2493. {
  2494. union
  2495. {
  2496. asSIMPLEMETHOD_t mthd;
  2497. asFUNCTION_t func;
  2498. } p;
  2499. p.func = (void (*)())(i->func);
  2500. int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())p.mthd;
  2501. return (((asCSimpleDummy*)obj)->*f)();
  2502. }
  2503. else
  2504. #endif
  2505. if( i->callConv == ICC_GENERIC_METHOD )
  2506. {
  2507. asCGeneric gen(this, s, obj, 0);
  2508. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2509. f(&gen);
  2510. return *(int*)gen.GetReturnPointer();
  2511. }
  2512. else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/
  2513. {
  2514. int (*f)(void *) = (int (*)(void *))(i->func);
  2515. return f(obj);
  2516. }
  2517. #endif
  2518. }
  2519. void *asCScriptEngine::CallGlobalFunctionRetPtr(int func)
  2520. {
  2521. asCScriptFunction *s = scriptFunctions[func];
  2522. return CallGlobalFunctionRetPtr(s->sysFuncIntf, s);
  2523. }
  2524. void *asCScriptEngine::CallGlobalFunctionRetPtr(int func, void *param1)
  2525. {
  2526. asCScriptFunction *s = scriptFunctions[func];
  2527. return CallGlobalFunctionRetPtr(s->sysFuncIntf, s, param1);
  2528. }
  2529. void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s)
  2530. {
  2531. if( i->callConv == ICC_CDECL )
  2532. {
  2533. void *(*f)() = (void *(*)())(i->func);
  2534. return f();
  2535. }
  2536. else if( i->callConv == ICC_STDCALL )
  2537. {
  2538. void *(STDCALL *f)() = (void *(STDCALL *)())(i->func);
  2539. return f();
  2540. }
  2541. else
  2542. {
  2543. asCGeneric gen(this, s, 0, 0);
  2544. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2545. f(&gen);
  2546. return *(void**)gen.GetReturnPointer();
  2547. }
  2548. }
  2549. void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1)
  2550. {
  2551. if( i->callConv == ICC_CDECL )
  2552. {
  2553. void *(*f)(void *) = (void *(*)(void *))(i->func);
  2554. return f(param1);
  2555. }
  2556. else if( i->callConv == ICC_STDCALL )
  2557. {
  2558. void *(STDCALL *f)(void *) = (void *(STDCALL *)(void *))(i->func);
  2559. return f(param1);
  2560. }
  2561. else
  2562. {
  2563. asCGeneric gen(this, s, 0, (asDWORD*)&param1);
  2564. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2565. f(&gen);
  2566. return *(void**)gen.GetReturnPointer();
  2567. }
  2568. }
  2569. void asCScriptEngine::CallObjectMethod(void *obj, void *param, int func)
  2570. {
  2571. asCScriptFunction *s = scriptFunctions[func];
  2572. CallObjectMethod(obj, param, s->sysFuncIntf, s);
  2573. }
  2574. void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *i, asCScriptFunction *s)
  2575. {
  2576. #ifdef __GNUC__
  2577. if( i->callConv == ICC_CDECL_OBJLAST )
  2578. {
  2579. void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
  2580. f(param, obj);
  2581. }
  2582. else if( i->callConv == ICC_GENERIC_METHOD )
  2583. {
  2584. asCGeneric gen(this, s, obj, (asDWORD*)&param);
  2585. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2586. f(&gen);
  2587. }
  2588. else /*if( i->callConv == ICC_CDECL_OBJFIRST || i->callConv == ICC_THISCALL )*/
  2589. {
  2590. void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
  2591. f(obj, param);
  2592. }
  2593. #else
  2594. #ifndef AS_NO_CLASS_METHODS
  2595. if( i->callConv == ICC_THISCALL )
  2596. {
  2597. union
  2598. {
  2599. asSIMPLEMETHOD_t mthd;
  2600. asFUNCTION_t func;
  2601. } p;
  2602. p.func = (void (*)())(i->func);
  2603. void (asCSimpleDummy::*f)(void *) = (void (asCSimpleDummy::*)(void *))(p.mthd);
  2604. (((asCSimpleDummy*)obj)->*f)(param);
  2605. }
  2606. else
  2607. #endif
  2608. if( i->callConv == ICC_CDECL_OBJLAST )
  2609. {
  2610. void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
  2611. f(param, obj);
  2612. }
  2613. else if( i->callConv == ICC_GENERIC_METHOD )
  2614. {
  2615. asCGeneric gen(this, s, obj, (asDWORD*)&param);
  2616. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2617. f(&gen);
  2618. }
  2619. else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/
  2620. {
  2621. void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
  2622. f(obj, param);
  2623. }
  2624. #endif
  2625. }
  2626. void asCScriptEngine::CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s)
  2627. {
  2628. if( i->callConv == ICC_CDECL )
  2629. {
  2630. void (*f)(void *, void *) = (void (*)(void *, void *))(i->func);
  2631. f(param1, param2);
  2632. }
  2633. else if( i->callConv == ICC_STDCALL )
  2634. {
  2635. void (STDCALL *f)(void *, void *) = (void (STDCALL *)(void *, void *))(i->func);
  2636. f(param1, param2);
  2637. }
  2638. else
  2639. {
  2640. asCGeneric gen(this, s, 0, (asDWORD*)&param1);
  2641. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2642. f(&gen);
  2643. }
  2644. }
  2645. bool asCScriptEngine::CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s)
  2646. {
  2647. if( i->callConv == ICC_CDECL )
  2648. {
  2649. bool (*f)(void *, void *) = (bool (*)(void *, void *))(i->func);
  2650. return f(param1, param2);
  2651. }
  2652. else if( i->callConv == ICC_STDCALL )
  2653. {
  2654. bool (STDCALL *f)(void *, void *) = (bool (STDCALL *)(void *, void *))(i->func);
  2655. return f(param1, param2);
  2656. }
  2657. else
  2658. {
  2659. // TODO: When simulating a 64bit environment by defining AS_64BIT_PTR on a 32bit platform this code
  2660. // fails, because the stack given to asCGeneric is not prepared with two 64bit arguments.
  2661. asCGeneric gen(this, s, 0, (asDWORD*)&param1);
  2662. void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func);
  2663. f(&gen);
  2664. return *(bool*)gen.GetReturnPointer();
  2665. }
  2666. }
  2667. void *asCScriptEngine::CallAlloc(asCObjectType *type)
  2668. {
  2669. // Allocate 4 bytes as the smallest size. Otherwise CallSystemFunction may try to
  2670. // copy a DWORD onto a smaller memory block, in case the object type is return in registers.
  2671. #if defined(AS_DEBUG)
  2672. return ((asALLOCFUNCDEBUG_t)(userAlloc))(type->size < 4 ? 4 : type->size, __FILE__, __LINE__);
  2673. #else
  2674. return userAlloc(type->size < 4 ? 4 : type->size);
  2675. #endif
  2676. }
  2677. void asCScriptEngine::CallFree(void *obj)
  2678. {
  2679. userFree(obj);
  2680. }
  2681. // interface
  2682. void asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, int typeId)
  2683. {
  2684. asCObjectType *objType = GetObjectTypeFromTypeId(typeId);
  2685. gc.AddScriptObjectToGC(obj, objType);
  2686. }
  2687. // interface
  2688. int asCScriptEngine::GarbageCollect(asDWORD flags)
  2689. {
  2690. return gc.GarbageCollect(flags);
  2691. }
  2692. // interface
  2693. void asCScriptEngine::GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected)
  2694. {
  2695. gc.GetStatistics(currentSize, totalDestroyed, totalDetected);
  2696. }
  2697. // interface
  2698. void asCScriptEngine::GCEnumCallback(void *reference)
  2699. {
  2700. gc.GCEnumCallback(reference);
  2701. }
  2702. // TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it
  2703. int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dt)
  2704. {
  2705. if( dt.IsNullHandle() ) return 0;
  2706. // Find the existing type id
  2707. asSMapNode<int,asCDataType*> *cursor = 0;
  2708. mapTypeIdToDataType.MoveFirst(&cursor);
  2709. while( cursor )
  2710. {
  2711. if( mapTypeIdToDataType.GetValue(cursor)->IsEqualExceptRefAndConst(dt) )
  2712. return mapTypeIdToDataType.GetKey(cursor);
  2713. mapTypeIdToDataType.MoveNext(&cursor, cursor);
  2714. }
  2715. // The type id doesn't exist, create it
  2716. // Setup the basic type id
  2717. int typeId = typeIdSeqNbr++;
  2718. if( dt.GetObjectType() )
  2719. {
  2720. if( dt.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT;
  2721. else if( dt.GetObjectType()->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_SCRIPTARRAY; // TODO: Should be asTYPEID_TEMPLATE
  2722. else if( dt.GetObjectType()->flags & asOBJ_ENUM ); // TODO: Should we have a specific bit for this?
  2723. else typeId |= asTYPEID_APPOBJECT;
  2724. }
  2725. // Insert the basic object type
  2726. asCDataType *newDt = asNEW(asCDataType)(dt);
  2727. newDt->MakeReference(false);
  2728. newDt->MakeReadOnly(false);
  2729. newDt->MakeHandle(false);
  2730. mapTypeIdToDataType.Insert(typeId, newDt);
  2731. // If the object type supports object handles then register those types as well
  2732. // Note: Don't check for addref, as asOBJ_SCOPED don't have this
  2733. if( dt.IsObject() && dt.GetObjectType()->beh.release )
  2734. {
  2735. newDt = asNEW(asCDataType)(dt);
  2736. newDt->MakeReference(false);
  2737. newDt->MakeReadOnly(false);
  2738. newDt->MakeHandle(true);
  2739. newDt->MakeHandleToConst(false);
  2740. mapTypeIdToDataType.Insert(typeId | asTYPEID_OBJHANDLE, newDt);
  2741. newDt = asNEW(asCDataType)(dt);
  2742. newDt->MakeReference(false);
  2743. newDt->MakeReadOnly(false);
  2744. newDt->MakeHandle(true);
  2745. newDt->MakeHandleToConst(true);
  2746. mapTypeIdToDataType.Insert(typeId | asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST, newDt);
  2747. }
  2748. // Call the method recursively to get the correct type id
  2749. return GetTypeIdFromDataType(dt);
  2750. }
  2751. const asCDataType *asCScriptEngine::GetDataTypeFromTypeId(int typeId)
  2752. {
  2753. asSMapNode<int,asCDataType*> *cursor = 0;
  2754. if( mapTypeIdToDataType.MoveTo(&cursor, typeId) )
  2755. return mapTypeIdToDataType.GetValue(cursor);
  2756. return 0;
  2757. }
  2758. asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId)
  2759. {
  2760. asSMapNode<int,asCDataType*> *cursor = 0;
  2761. if( mapTypeIdToDataType.MoveTo(&cursor, typeId) )
  2762. return mapTypeIdToDataType.GetValue(cursor)->GetObjectType();
  2763. return 0;
  2764. }
  2765. void asCScriptEngine::RemoveFromTypeIdMap(asCObjectType *type)
  2766. {
  2767. asSMapNode<int,asCDataType*> *cursor = 0;
  2768. mapTypeIdToDataType.MoveFirst(&cursor);
  2769. while( cursor )
  2770. {
  2771. asCDataType *dt = mapTypeIdToDataType.GetValue(cursor);
  2772. asSMapNode<int,asCDataType*> *old = cursor;
  2773. mapTypeIdToDataType.MoveNext(&cursor, cursor);
  2774. if( dt->GetObjectType() == type )
  2775. {
  2776. asDELETE(dt,asCDataType);
  2777. mapTypeIdToDataType.Erase(old);
  2778. }
  2779. }
  2780. }
  2781. // interface
  2782. int asCScriptEngine::GetTypeIdByDecl(const char *decl)
  2783. {
  2784. asCDataType dt;
  2785. asCBuilder bld(this, 0);
  2786. int r = bld.ParseDataType(decl, &dt);
  2787. if( r < 0 )
  2788. return asINVALID_TYPE;
  2789. return GetTypeIdFromDataType(dt);
  2790. }
  2791. const char *asCScriptEngine::GetTypeDeclaration(int typeId)
  2792. {
  2793. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2794. if( dt == 0 ) return 0;
  2795. asASSERT(threadManager);
  2796. asCString *tempString = &threadManager->GetLocalData()->string;
  2797. *tempString = dt->Format();
  2798. return tempString->AddressOf();
  2799. }
  2800. int asCScriptEngine::GetSizeOfPrimitiveType(int typeId)
  2801. {
  2802. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2803. if( dt == 0 ) return 0;
  2804. if( !dt->IsPrimitive() ) return 0;
  2805. return dt->GetSizeInMemoryBytes();
  2806. }
  2807. void *asCScriptEngine::CreateScriptObject(int typeId)
  2808. {
  2809. // Make sure the type id is for an object type, and not a primitive or a handle
  2810. if( (typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR)) != typeId ) return 0;
  2811. if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) return 0;
  2812. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2813. // Is the type id valid?
  2814. if( !dt ) return 0;
  2815. // Allocate the memory
  2816. asCObjectType *objType = dt->GetObjectType();
  2817. void *ptr = 0;
  2818. // Construct the object
  2819. if( objType->flags & asOBJ_SCRIPT_OBJECT )
  2820. ptr = ScriptObjectFactory(objType, this);
  2821. else if( objType->flags & asOBJ_TEMPLATE )
  2822. // The registered factory is moved to the construct behaviour when the type is instanciated
  2823. ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType);
  2824. else if( objType->flags & asOBJ_REF )
  2825. ptr = CallGlobalFunctionRetPtr(objType->beh.factory);
  2826. else
  2827. {
  2828. ptr = CallAlloc(objType);
  2829. int funcIndex = objType->beh.construct;
  2830. if( funcIndex )
  2831. CallObjectMethod(ptr, funcIndex);
  2832. }
  2833. return ptr;
  2834. }
  2835. void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, int typeId)
  2836. {
  2837. void *newObj = CreateScriptObject(typeId);
  2838. if( newObj == 0 ) return 0;
  2839. CopyScriptObject(newObj, origObj, typeId);
  2840. return newObj;
  2841. }
  2842. void asCScriptEngine::CopyScriptObject(void *dstObj, void *srcObj, int typeId)
  2843. {
  2844. // Make sure the type id is for an object type, and not a primitive or a handle
  2845. if( (typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR)) != typeId ) return;
  2846. if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) return;
  2847. // Copy the contents from the original object, using the assignment operator
  2848. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2849. // Is the type id valid?
  2850. if( !dt ) return;
  2851. asCObjectType *objType = dt->GetObjectType();
  2852. // TODO: beh.copy will be removed, so we need to find the default opAssign method instead
  2853. if( objType->beh.copy )
  2854. {
  2855. CallObjectMethod(dstObj, srcObj, objType->beh.copy);
  2856. }
  2857. else if( objType->size )
  2858. {
  2859. memcpy(dstObj, srcObj, objType->size);
  2860. }
  2861. }
  2862. void asCScriptEngine::AddRefScriptObject(void *obj, int typeId)
  2863. {
  2864. // Make sure it is not a null pointer
  2865. if( obj == 0 ) return;
  2866. // Make sure the type id is for an object type or a handle
  2867. if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) return;
  2868. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2869. // Is the type id valid?
  2870. if( !dt ) return;
  2871. asCObjectType *objType = dt->GetObjectType();
  2872. if( objType->beh.addref )
  2873. {
  2874. // Call the addref behaviour
  2875. CallObjectMethod(obj, objType->beh.addref);
  2876. }
  2877. }
  2878. void asCScriptEngine::ReleaseScriptObject(void *obj, int typeId)
  2879. {
  2880. // Make sure it is not a null pointer
  2881. if( obj == 0 ) return;
  2882. // Make sure the type id is for an object type or a handle
  2883. if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) return;
  2884. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  2885. // Is the type id valid?
  2886. if( !dt ) return;
  2887. asCObjectType *objType = dt->GetObjectType();
  2888. if( objType->beh.release )
  2889. {
  2890. // Call the release behaviour
  2891. CallObjectMethod(obj, objType->beh.release);
  2892. }
  2893. else
  2894. {
  2895. // Call the destructor
  2896. if( objType->beh.destruct )
  2897. CallObjectMethod(obj, objType->beh.destruct);
  2898. // Then free the memory
  2899. CallFree(obj);
  2900. }
  2901. }
  2902. bool asCScriptEngine::IsHandleCompatibleWithObject(void *obj, int objTypeId, int handleTypeId)
  2903. {
  2904. // if equal, then it is obvious they are compatible
  2905. if( objTypeId == handleTypeId )
  2906. return true;
  2907. // Get the actual data types from the type ids
  2908. const asCDataType *objDt = GetDataTypeFromTypeId(objTypeId);
  2909. const asCDataType *hdlDt = GetDataTypeFromTypeId(handleTypeId);
  2910. // A handle to const cannot be passed to a handle that is not referencing a const object
  2911. if( objDt->IsHandleToConst() && !hdlDt->IsHandleToConst() )
  2912. return false;
  2913. if( objDt->GetObjectType() == hdlDt->GetObjectType() )
  2914. {
  2915. // The object type is equal
  2916. return true;
  2917. }
  2918. else if( objDt->IsScriptObject() && obj )
  2919. {
  2920. // There's still a chance the object implements the requested interface
  2921. asCObjectType *objType = ((asCScriptObject*)obj)->objType;
  2922. if( objType->Implements(hdlDt->GetObjectType()) )
  2923. return true;
  2924. }
  2925. return false;
  2926. }
  2927. int asCScriptEngine::BeginConfigGroup(const char *groupName)
  2928. {
  2929. // Make sure the group name doesn't already exist
  2930. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  2931. {
  2932. if( configGroups[n]->groupName == groupName )
  2933. return asNAME_TAKEN;
  2934. }
  2935. if( currentGroup != &defaultGroup )
  2936. return asNOT_SUPPORTED;
  2937. asCConfigGroup *group = asNEW(asCConfigGroup)();
  2938. group->groupName = groupName;
  2939. configGroups.PushLast(group);
  2940. currentGroup = group;
  2941. return 0;
  2942. }
  2943. int asCScriptEngine::EndConfigGroup()
  2944. {
  2945. // Raise error if trying to end the default config
  2946. if( currentGroup == &defaultGroup )
  2947. return asNOT_SUPPORTED;
  2948. currentGroup = &defaultGroup;
  2949. return 0;
  2950. }
  2951. int asCScriptEngine::RemoveConfigGroup(const char *groupName)
  2952. {
  2953. // It is not allowed to remove a group that is still in use.
  2954. // It would be possible to change the code in such a way that
  2955. // the group could be removed even though it was still in use,
  2956. // but that would cause severe negative impact on runtime
  2957. // performance, since the VM would then have to be able handle
  2958. // situations where the types, functions, and global variables
  2959. // can be removed at any time.
  2960. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  2961. {
  2962. if( configGroups[n]->groupName == groupName )
  2963. {
  2964. asCConfigGroup *group = configGroups[n];
  2965. // Make sure the group isn't referenced by anyone
  2966. if( group->refCount > 0 )
  2967. return asCONFIG_GROUP_IS_IN_USE;
  2968. // Verify if any objects registered in this group is still alive
  2969. if( group->HasLiveObjects() )
  2970. return asCONFIG_GROUP_IS_IN_USE;
  2971. // Remove the group from the list
  2972. if( n == configGroups.GetLength() - 1 )
  2973. configGroups.PopLast();
  2974. else
  2975. configGroups[n] = configGroups.PopLast();
  2976. // Remove the configurations registered with this group
  2977. group->RemoveConfiguration(this);
  2978. asDELETE(group,asCConfigGroup);
  2979. }
  2980. }
  2981. return 0;
  2982. }
  2983. asCConfigGroup *asCScriptEngine::FindConfigGroupForFunction(int funcId)
  2984. {
  2985. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  2986. {
  2987. // Check global functions
  2988. asUINT m;
  2989. for( m = 0; m < configGroups[n]->scriptFunctions.GetLength(); m++ )
  2990. {
  2991. if( configGroups[n]->scriptFunctions[m]->id == funcId )
  2992. return configGroups[n];
  2993. }
  2994. }
  2995. return 0;
  2996. }
  2997. asCConfigGroup *asCScriptEngine::FindConfigGroupForGlobalVar(int gvarId)
  2998. {
  2999. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  3000. {
  3001. for( asUINT m = 0; m < configGroups[n]->globalProps.GetLength(); m++ )
  3002. {
  3003. if( configGroups[n]->globalProps[m]->id == gvarId )
  3004. return configGroups[n];
  3005. }
  3006. }
  3007. return 0;
  3008. }
  3009. asCConfigGroup *asCScriptEngine::FindConfigGroupForObjectType(const asCObjectType *objType)
  3010. {
  3011. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  3012. {
  3013. for( asUINT m = 0; m < configGroups[n]->objTypes.GetLength(); m++ )
  3014. {
  3015. if( configGroups[n]->objTypes[m] == objType )
  3016. return configGroups[n];
  3017. }
  3018. }
  3019. return 0;
  3020. }
  3021. int asCScriptEngine::SetConfigGroupModuleAccess(const char *groupName, const char *module, bool hasAccess)
  3022. {
  3023. asCConfigGroup *group = 0;
  3024. // Make sure the group name doesn't already exist
  3025. for( asUINT n = 0; n < configGroups.GetLength(); n++ )
  3026. {
  3027. if( configGroups[n]->groupName == groupName )
  3028. {
  3029. group = configGroups[n];
  3030. break;
  3031. }
  3032. }
  3033. if( group == 0 )
  3034. return asWRONG_CONFIG_GROUP;
  3035. return group->SetModuleAccess(module, hasAccess);
  3036. }
  3037. int asCScriptEngine::GetNextScriptFunctionId()
  3038. {
  3039. if( freeScriptFunctionIds.GetLength() )
  3040. return freeScriptFunctionIds.PopLast();
  3041. int id = (int)scriptFunctions.GetLength();
  3042. scriptFunctions.PushLast(0);
  3043. return id;
  3044. }
  3045. void asCScriptEngine::SetScriptFunction(asCScriptFunction *func)
  3046. {
  3047. scriptFunctions[func->id] = func;
  3048. }
  3049. void asCScriptEngine::FreeScriptFunctionId(int id)
  3050. {
  3051. if( id < 0 ) return;
  3052. id &= 0xFFFF;
  3053. if( id >= (int)scriptFunctions.GetLength() ) return;
  3054. if( scriptFunctions[id] )
  3055. {
  3056. asCScriptFunction *func = scriptFunctions[id];
  3057. // Remove the function from the list of script functions
  3058. if( id == (int)scriptFunctions.GetLength() - 1 )
  3059. {
  3060. scriptFunctions.PopLast();
  3061. }
  3062. else
  3063. {
  3064. scriptFunctions[id] = 0;
  3065. freeScriptFunctionIds.PushLast(id);
  3066. }
  3067. // Is the function used as signature id?
  3068. if( func->signatureId == id )
  3069. {
  3070. // Remove the signature id
  3071. signatureIds.RemoveValue(func);
  3072. // Update all functions using the signature id
  3073. int newSigId = 0;
  3074. for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ )
  3075. {
  3076. if( scriptFunctions[n] && scriptFunctions[n]->signatureId == id )
  3077. {
  3078. if( newSigId == 0 )
  3079. {
  3080. newSigId = scriptFunctions[n]->id;
  3081. signatureIds.PushLast(scriptFunctions[n]);
  3082. }
  3083. scriptFunctions[n]->signatureId = newSigId;
  3084. }
  3085. }
  3086. }
  3087. }
  3088. }
  3089. // interface
  3090. // TODO: typedef: Accept complex types for the typedefs
  3091. int asCScriptEngine::RegisterTypedef(const char *type, const char *decl)
  3092. {
  3093. if( type == 0 ) return ConfigError(asINVALID_NAME);
  3094. // Verify if the name has been registered as a type already
  3095. asUINT n;
  3096. for( n = 0; n < objectTypes.GetLength(); n++ )
  3097. {
  3098. if( objectTypes[n] && objectTypes[n]->name == type )
  3099. return asALREADY_REGISTERED;
  3100. }
  3101. // Grab the data type
  3102. asCTokenizer t;
  3103. size_t tokenLen;
  3104. eTokenType token;
  3105. asCDataType dataType;
  3106. // Create the data type
  3107. token = t.GetToken(decl, strlen(decl), &tokenLen);
  3108. switch(token)
  3109. {
  3110. case ttBool:
  3111. case ttInt:
  3112. case ttInt8:
  3113. case ttInt16:
  3114. case ttInt64:
  3115. case ttUInt:
  3116. case ttUInt8:
  3117. case ttUInt16:
  3118. case ttUInt64:
  3119. case ttFloat:
  3120. case ttDouble:
  3121. if( strlen(decl) != tokenLen )
  3122. {
  3123. return ConfigError(asINVALID_TYPE);
  3124. }
  3125. break;
  3126. default:
  3127. return ConfigError(asINVALID_TYPE);
  3128. }
  3129. dataType = asCDataType::CreatePrimitive(token, false);
  3130. // Make sure the name is not a reserved keyword
  3131. token = t.GetToken(type, strlen(type), &tokenLen);
  3132. if( token != ttIdentifier || strlen(type) != tokenLen )
  3133. return ConfigError(asINVALID_NAME);
  3134. asCBuilder bld(this, 0);
  3135. int r = bld.CheckNameConflict(type, 0, 0);
  3136. if( r < 0 )
  3137. return ConfigError(asNAME_TAKEN);
  3138. // Don't have to check against members of object
  3139. // types as they are allowed to use the names
  3140. // Put the data type in the list
  3141. asCObjectType *object= asNEW(asCObjectType)(this);
  3142. object->flags = asOBJ_TYPEDEF;
  3143. object->size = dataType.GetSizeInMemoryBytes();
  3144. object->name = type;
  3145. object->templateSubType = dataType;
  3146. objectTypes.PushLast(object);
  3147. registeredTypeDefs.PushLast(object);
  3148. currentGroup->objTypes.PushLast(object);
  3149. return asSUCCESS;
  3150. }
  3151. // interface
  3152. int asCScriptEngine::GetTypedefCount()
  3153. {
  3154. return (int)registeredTypeDefs.GetLength();
  3155. }
  3156. // interface
  3157. const char *asCScriptEngine::GetTypedefByIndex(asUINT index, int *typeId, const char **configGroup)
  3158. {
  3159. if( index >= registeredTypeDefs.GetLength() )
  3160. return 0;
  3161. if( typeId )
  3162. *typeId = GetTypeIdByDecl(registeredTypeDefs[index]->name.AddressOf());
  3163. if( configGroup )
  3164. {
  3165. asCConfigGroup *group = FindConfigGroupForObjectType(registeredTypeDefs[index]);
  3166. if( group )
  3167. *configGroup = group->groupName.AddressOf();
  3168. else
  3169. *configGroup = 0;
  3170. }
  3171. return registeredTypeDefs[index]->name.AddressOf();
  3172. }
  3173. // interface
  3174. int asCScriptEngine::RegisterEnum(const char *name)
  3175. {
  3176. // Check the name
  3177. if( NULL == name )
  3178. return ConfigError(asINVALID_NAME);
  3179. // Verify if the name has been registered as a type already
  3180. asUINT n;
  3181. for( n = 0; n < objectTypes.GetLength(); n++ )
  3182. if( objectTypes[n] && objectTypes[n]->name == name )
  3183. return asALREADY_REGISTERED;
  3184. // Use builder to parse the datatype
  3185. asCDataType dt;
  3186. asCBuilder bld(this, 0);
  3187. bool oldMsgCallback = msgCallback; msgCallback = false;
  3188. int r = bld.ParseDataType(name, &dt);
  3189. msgCallback = oldMsgCallback;
  3190. if( r >= 0 )
  3191. return ConfigError(asERROR);
  3192. // Make sure the name is not a reserved keyword
  3193. asCTokenizer t;
  3194. size_t tokenLen;
  3195. int token = t.GetToken(name, strlen(name), &tokenLen);
  3196. if( token != ttIdentifier || strlen(name) != tokenLen )
  3197. return ConfigError(asINVALID_NAME);
  3198. r = bld.CheckNameConflict(name, 0, 0);
  3199. if( r < 0 )
  3200. return ConfigError(asNAME_TAKEN);
  3201. asCObjectType *st = asNEW(asCObjectType)(this);
  3202. asCDataType dataType;
  3203. dataType.CreatePrimitive(ttInt, false);
  3204. st->flags = asOBJ_ENUM;
  3205. st->size = dataType.GetSizeInMemoryBytes();
  3206. st->name = name;
  3207. objectTypes.PushLast(st);
  3208. registeredEnums.PushLast(st);
  3209. currentGroup->objTypes.PushLast(st);
  3210. return asSUCCESS;
  3211. }
  3212. // interface
  3213. int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueName, int value)
  3214. {
  3215. // Verify that the correct config group is used
  3216. if( currentGroup->FindType(typeName) == 0 )
  3217. return asWRONG_CONFIG_GROUP;
  3218. asCDataType dt;
  3219. int r;
  3220. asCBuilder bld(this, 0);
  3221. r = bld.ParseDataType(typeName, &dt);
  3222. if( r < 0 )
  3223. return ConfigError(r);
  3224. // Store the enum value
  3225. asCObjectType *ot = dt.GetObjectType();
  3226. if( ot == 0 || !(ot->flags & asOBJ_ENUM) )
  3227. return ConfigError(asINVALID_TYPE);
  3228. if( NULL == valueName )
  3229. return ConfigError(asINVALID_NAME);
  3230. for( unsigned int n = 0; n < ot->enumValues.GetLength(); n++ )
  3231. {
  3232. if( ot->enumValues[n]->name == valueName )
  3233. return ConfigError(asALREADY_REGISTERED);
  3234. }
  3235. asSEnumValue *e = asNEW(asSEnumValue);
  3236. e->name = valueName;
  3237. e->value = value;
  3238. ot->enumValues.PushLast(e);
  3239. return asSUCCESS;
  3240. }
  3241. // interface
  3242. int asCScriptEngine::GetEnumCount()
  3243. {
  3244. return (int)registeredEnums.GetLength();
  3245. }
  3246. // interface
  3247. const char *asCScriptEngine::GetEnumByIndex(asUINT index, int *enumTypeId, const char **configGroup)
  3248. {
  3249. if( index >= registeredEnums.GetLength() )
  3250. return 0;
  3251. if( configGroup )
  3252. {
  3253. asCConfigGroup *group = FindConfigGroupForObjectType(registeredEnums[index]);
  3254. if( group )
  3255. *configGroup = group->groupName.AddressOf();
  3256. else
  3257. *configGroup = 0;
  3258. }
  3259. if( enumTypeId )
  3260. *enumTypeId = GetTypeIdByDecl(registeredEnums[index]->name.AddressOf());
  3261. return registeredEnums[index]->name.AddressOf();
  3262. }
  3263. // interface
  3264. int asCScriptEngine::GetEnumValueCount(int enumTypeId)
  3265. {
  3266. const asCDataType *dt = GetDataTypeFromTypeId(enumTypeId);
  3267. asCObjectType *t = dt->GetObjectType();
  3268. if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) )
  3269. return asINVALID_TYPE;
  3270. return (int)t->enumValues.GetLength();
  3271. }
  3272. // interface
  3273. const char *asCScriptEngine::GetEnumValueByIndex(int enumTypeId, asUINT index, int *outValue)
  3274. {
  3275. // TODO: This same function is implemented in as_module.cpp as well. Perhaps it should be moved to asCObjectType?
  3276. const asCDataType *dt = GetDataTypeFromTypeId(enumTypeId);
  3277. asCObjectType *t = dt->GetObjectType();
  3278. if( t == 0 || !(t->GetFlags() & asOBJ_ENUM) )
  3279. return 0;
  3280. if( index >= t->enumValues.GetLength() )
  3281. return 0;
  3282. if( outValue )
  3283. *outValue = t->enumValues[index]->value;
  3284. return t->enumValues[index]->name.AddressOf();
  3285. }
  3286. // interface
  3287. int asCScriptEngine::GetObjectTypeCount()
  3288. {
  3289. return (int)registeredObjTypes.GetLength();
  3290. }
  3291. // interface
  3292. asIObjectType *asCScriptEngine::GetObjectTypeByIndex(asUINT index)
  3293. {
  3294. if( index >= registeredObjTypes.GetLength() )
  3295. return 0;
  3296. return registeredObjTypes[index];
  3297. }
  3298. // interface
  3299. asIObjectType *asCScriptEngine::GetObjectTypeById(int typeId)
  3300. {
  3301. const asCDataType *dt = GetDataTypeFromTypeId(typeId);
  3302. // Is the type id valid?
  3303. if( !dt ) return 0;
  3304. // Enum types are not objects, so we shouldn't return an object type for them
  3305. if( dt->GetObjectType() && dt->GetObjectType()->GetFlags() & asOBJ_ENUM )
  3306. return 0;
  3307. return dt->GetObjectType();
  3308. }
  3309. asIScriptFunction *asCScriptEngine::GetFunctionDescriptorById(int funcId)
  3310. {
  3311. return GetScriptFunction(funcId);
  3312. }
  3313. // internal
  3314. bool asCScriptEngine::IsTemplateType(const char *name)
  3315. {
  3316. // TODO: optimize: Improve linear search
  3317. for( unsigned int n = 0; n < objectTypes.GetLength(); n++ )
  3318. {
  3319. if( objectTypes[n] && objectTypes[n]->name == name )
  3320. {
  3321. return objectTypes[n]->flags & asOBJ_TEMPLATE ? true : false;
  3322. }
  3323. }
  3324. return false;
  3325. }
  3326. // internal
  3327. int asCScriptEngine::AddConstantString(const char *str, size_t len)
  3328. {
  3329. // The str may contain null chars, so we cannot use strlen, or strcmp, or strcpy
  3330. // TODO: optimize: Improve linear search
  3331. // Has the string been registered before?
  3332. for( size_t n = 0; n < stringConstants.GetLength(); n++ )
  3333. {
  3334. if( stringConstants[n]->Compare(str, len) == 0 )
  3335. {
  3336. return (int)n;
  3337. }
  3338. }
  3339. // No match was found, add the string
  3340. asCString *cstr = asNEW(asCString)(str, len);
  3341. stringConstants.PushLast(cstr);
  3342. // The VM currently doesn't handle string ids larger than 65535
  3343. asASSERT(stringConstants.GetLength() <= 65536);
  3344. return (int)stringConstants.GetLength() - 1;
  3345. }
  3346. // internal
  3347. const asCString &asCScriptEngine::GetConstantString(int id)
  3348. {
  3349. return *stringConstants[id];
  3350. }
  3351. // internal
  3352. int asCScriptEngine::GetScriptSectionNameIndex(const char *name)
  3353. {
  3354. // TODO: These names are only released when the engine is freed. The assumption is that
  3355. // the same script section names will be reused instead of there always being new
  3356. // names. Is this assumption valid? Do we need to add reference counting?
  3357. // Store the script section names for future reference
  3358. for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ )
  3359. {
  3360. if( scriptSectionNames[n]->Compare(name) == 0 )
  3361. return n;
  3362. }
  3363. scriptSectionNames.PushLast(asNEW(asCString)(name));
  3364. return int(scriptSectionNames.GetLength()-1);
  3365. }
  3366. END_AS_NAMESPACE