as_builder.cpp 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2011 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. [email protected]
  22. */
  23. // Modified by Lasse Öörni for Urho3D
  24. //
  25. // as_builder.cpp
  26. //
  27. // This is the class that manages the compilation of the scripts
  28. //
  29. #include "as_config.h"
  30. #include "as_builder.h"
  31. #include "as_parser.h"
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_string_util.h"
  35. #include "as_outputbuffer.h"
  36. #include "as_texts.h"
  37. #include "as_scriptobject.h"
  38. BEGIN_AS_NAMESPACE
  39. asCBuilder::asCBuilder(asCScriptEngine *engine, asCModule *module)
  40. {
  41. this->engine = engine;
  42. this->module = module;
  43. }
  44. asCBuilder::~asCBuilder()
  45. {
  46. asUINT n;
  47. // Free all functions
  48. for( n = 0; n < functions.GetLength(); n++ )
  49. {
  50. if( functions[n] )
  51. {
  52. if( functions[n]->node )
  53. {
  54. functions[n]->node->Destroy(engine);
  55. }
  56. asDELETE(functions[n],sFunctionDescription);
  57. }
  58. functions[n] = 0;
  59. }
  60. // Free all global variables
  61. for( n = 0; n < globVariables.GetLength(); n++ )
  62. {
  63. if( globVariables[n] )
  64. {
  65. if( globVariables[n]->nextNode )
  66. {
  67. globVariables[n]->nextNode->Destroy(engine);
  68. }
  69. asDELETE(globVariables[n],sGlobalVariableDescription);
  70. globVariables[n] = 0;
  71. }
  72. }
  73. // Free all the loaded files
  74. for( n = 0; n < scripts.GetLength(); n++ )
  75. {
  76. if( scripts[n] )
  77. {
  78. asDELETE(scripts[n],asCScriptCode);
  79. }
  80. scripts[n] = 0;
  81. }
  82. // Free all class declarations
  83. for( n = 0; n < classDeclarations.GetLength(); n++ )
  84. {
  85. if( classDeclarations[n] )
  86. {
  87. if( classDeclarations[n]->node )
  88. {
  89. classDeclarations[n]->node->Destroy(engine);
  90. }
  91. asDELETE(classDeclarations[n],sClassDeclaration);
  92. classDeclarations[n] = 0;
  93. }
  94. }
  95. for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
  96. {
  97. if( interfaceDeclarations[n] )
  98. {
  99. if( interfaceDeclarations[n]->node )
  100. {
  101. interfaceDeclarations[n]->node->Destroy(engine);
  102. }
  103. asDELETE(interfaceDeclarations[n],sClassDeclaration);
  104. interfaceDeclarations[n] = 0;
  105. }
  106. }
  107. for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
  108. {
  109. if( namedTypeDeclarations[n] )
  110. {
  111. if( namedTypeDeclarations[n]->node )
  112. {
  113. namedTypeDeclarations[n]->node->Destroy(engine);
  114. }
  115. asDELETE(namedTypeDeclarations[n],sClassDeclaration);
  116. namedTypeDeclarations[n] = 0;
  117. }
  118. }
  119. for( n = 0; n < funcDefs.GetLength(); n++ )
  120. {
  121. if( funcDefs[n] )
  122. {
  123. if( funcDefs[n]->node )
  124. funcDefs[n]->node->Destroy(engine);
  125. asDELETE(funcDefs[n],sFuncDef);
  126. funcDefs[n] = 0;
  127. }
  128. }
  129. }
  130. int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy)
  131. {
  132. asCScriptCode *script = asNEW(asCScriptCode);
  133. int r = script->SetCode(name, code, codeLength, makeCopy);
  134. script->lineOffset = lineOffset;
  135. script->idx = sectionIdx;
  136. scripts.PushLast(script);
  137. return r;
  138. }
  139. int asCBuilder::Build()
  140. {
  141. numErrors = 0;
  142. numWarnings = 0;
  143. preMessage.isSet = false;
  144. ParseScripts();
  145. CompileClasses();
  146. CompileGlobalVariables();
  147. CompileFunctions();
  148. if( numErrors > 0 )
  149. return asERROR;
  150. return asSUCCESS;
  151. }
  152. int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset)
  153. {
  154. numErrors = 0;
  155. numWarnings = 0;
  156. preMessage.isSet = false;
  157. // Add the string to the script code
  158. asCScriptCode *script = asNEW(asCScriptCode);
  159. script->SetCode(sectionName, code, true);
  160. script->lineOffset = lineOffset;
  161. scripts.PushLast(script);
  162. // Parse the string
  163. asCParser parser(this);
  164. if( parser.ParseScript(scripts[0]) < 0 )
  165. return asERROR;
  166. asCScriptNode *node = parser.GetScriptNode();
  167. // Make sure there is nothing else than the global variable in the script code
  168. if( node == 0 ||
  169. node->firstChild == 0 ||
  170. node->firstChild != node->lastChild ||
  171. node->firstChild->nodeType != snGlobalVar )
  172. {
  173. WriteError(script->name.AddressOf(), TXT_ONLY_ONE_VARIABLE_ALLOWED, 0, 0);
  174. return asERROR;
  175. }
  176. node = node->firstChild;
  177. node->DisconnectParent();
  178. RegisterGlobalVar(node, script);
  179. CompileGlobalVariables();
  180. if( numErrors > 0 )
  181. {
  182. // Remove the variable from the module, if it was registered
  183. if( globVariables.GetLength() > 0 )
  184. {
  185. module->RemoveGlobalVar(module->GetGlobalVarCount()-1);
  186. }
  187. return asERROR;
  188. }
  189. return 0;
  190. }
  191. int asCBuilder::ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func)
  192. {
  193. int firstArgWithDefaultValue = -1;
  194. for( asUINT n = 0; n < func->defaultArgs.GetLength(); n++ )
  195. {
  196. if( func->defaultArgs[n] )
  197. firstArgWithDefaultValue = n;
  198. else if( firstArgWithDefaultValue >= 0 )
  199. {
  200. int r, c;
  201. script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  202. asCString str;
  203. str.Format(TXT_DEF_ARG_MISSING_IN_FUNC_s, func->GetDeclaration());
  204. WriteError(script->name.AddressOf(), str.AddressOf(), r, c);
  205. return asINVALID_DECLARATION;
  206. }
  207. }
  208. return 0;
  209. }
  210. int asCBuilder::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc)
  211. {
  212. asASSERT(outFunc != 0);
  213. numErrors = 0;
  214. numWarnings = 0;
  215. preMessage.isSet = false;
  216. // Add the string to the script code
  217. asCScriptCode *script = asNEW(asCScriptCode);
  218. script->SetCode(sectionName, code, true);
  219. script->lineOffset = lineOffset;
  220. scripts.PushLast(script);
  221. // Parse the string
  222. asCParser parser(this);
  223. if( parser.ParseScript(scripts[0]) < 0 )
  224. return asERROR;
  225. asCScriptNode *node = parser.GetScriptNode();
  226. // Make sure there is nothing else than the function in the script code
  227. if( node == 0 ||
  228. node->firstChild == 0 ||
  229. node->firstChild != node->lastChild ||
  230. node->firstChild->nodeType != snFunction )
  231. {
  232. WriteError(script->name.AddressOf(), TXT_ONLY_ONE_FUNCTION_ALLOWED, 0, 0);
  233. return asERROR;
  234. }
  235. // Find the function node
  236. node = node->firstChild;
  237. // Create the function
  238. bool isConstructor, isDestructor, isPrivate;
  239. asCScriptFunction *func = asNEW(asCScriptFunction)(engine,module,asFUNC_SCRIPT);
  240. GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterTypes, func->inOutFlags, func->defaultArgs, func->isReadOnly, isConstructor, isDestructor, isPrivate);
  241. func->id = engine->GetNextScriptFunctionId();
  242. func->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : "");
  243. // Make sure the default args are declared correctly
  244. int r = ValidateDefaultArgs(script, node, func);
  245. if( r < 0 )
  246. {
  247. func->Release();
  248. return asERROR;
  249. }
  250. // Tell the engine that the function exists already so the compiler can access it
  251. if( compileFlags & asCOMP_ADD_TO_MODULE )
  252. {
  253. int r = CheckNameConflict(func->name.AddressOf(), node, scripts[0]);
  254. if( r < 0 )
  255. {
  256. func->Release();
  257. return asERROR;
  258. }
  259. module->globalFunctions.PushLast(func);
  260. func->AddRef();
  261. module->AddScriptFunction(func);
  262. }
  263. else
  264. engine->SetScriptFunction(func);
  265. // Fill in the function info for the builder too
  266. node->DisconnectParent();
  267. sFunctionDescription *funcDesc = asNEW(sFunctionDescription);
  268. functions.PushLast(funcDesc);
  269. funcDesc->script = scripts[0];
  270. funcDesc->node = node;
  271. funcDesc->name = func->name;
  272. funcDesc->funcId = func->id;
  273. asCCompiler compiler(engine);
  274. if( compiler.CompileFunction(this, functions[0]->script, functions[0]->node, func) >= 0 )
  275. {
  276. // Return the function
  277. *outFunc = func;
  278. }
  279. else
  280. {
  281. // If the function was added to the module then remove it again
  282. if( compileFlags & asCOMP_ADD_TO_MODULE )
  283. {
  284. module->globalFunctions.RemoveValue(func);
  285. module->scriptFunctions.RemoveValue(func);
  286. func->Release();
  287. func->Release();
  288. }
  289. func->Release();
  290. return asERROR;
  291. }
  292. return asSUCCESS;
  293. }
  294. void asCBuilder::ParseScripts()
  295. {
  296. asCArray<asCParser*> parsers((int)scripts.GetLength());
  297. // Parse all the files as if they were one
  298. asUINT n = 0;
  299. for( n = 0; n < scripts.GetLength(); n++ )
  300. {
  301. asCParser *parser = asNEW(asCParser)(this);
  302. parsers.PushLast(parser);
  303. // Parse the script file
  304. parser->ParseScript(scripts[n]);
  305. }
  306. if( numErrors == 0 )
  307. {
  308. // Find all type declarations
  309. for( n = 0; n < scripts.GetLength(); n++ )
  310. {
  311. asCScriptNode *node = parsers[n]->GetScriptNode();
  312. // Find structure definitions first
  313. node = node->firstChild;
  314. while( node )
  315. {
  316. asCScriptNode *next = node->next;
  317. if( node->nodeType == snClass )
  318. {
  319. node->DisconnectParent();
  320. RegisterClass(node, scripts[n]);
  321. }
  322. else if( node->nodeType == snInterface )
  323. {
  324. node->DisconnectParent();
  325. RegisterInterface(node, scripts[n]);
  326. }
  327. // Handle enumeration
  328. else if( node->nodeType == snEnum )
  329. {
  330. node->DisconnectParent();
  331. RegisterEnum(node, scripts[n]);
  332. }
  333. // Handle typedef
  334. else if( node->nodeType == snTypedef )
  335. {
  336. node->DisconnectParent();
  337. RegisterTypedef(node, scripts[n]);
  338. }
  339. else if( node->nodeType == snFuncDef )
  340. {
  341. node->DisconnectParent();
  342. RegisterFuncDef(node, scripts[n]);
  343. }
  344. node = next;
  345. }
  346. }
  347. // Register the complete function definitions
  348. for( n = 0; n < funcDefs.GetLength(); n++ )
  349. {
  350. CompleteFuncDef(funcDefs[n]);
  351. }
  352. // Register script methods found in the interfaces
  353. for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
  354. {
  355. sClassDeclaration *decl = interfaceDeclarations[n];
  356. asCScriptNode *node = decl->node->firstChild->next;
  357. while( node )
  358. {
  359. asCScriptNode *next = node->next;
  360. if( node->nodeType == snFunction )
  361. {
  362. node->DisconnectParent();
  363. RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType, true);
  364. }
  365. node = next;
  366. }
  367. }
  368. // Now the interfaces have been completely established, now we need to determine if
  369. // the same interface has already been registered before, and if so reuse the interface id.
  370. module->ResolveInterfaceIds();
  371. // Register script methods found in the structures
  372. for( n = 0; n < classDeclarations.GetLength(); n++ )
  373. {
  374. sClassDeclaration *decl = classDeclarations[n];
  375. asCScriptNode *node = decl->node->firstChild->next;
  376. // Skip list of classes and interfaces
  377. while( node && node->nodeType == snIdentifier )
  378. node = node->next;
  379. while( node )
  380. {
  381. asCScriptNode *next = node->next;
  382. if( node->nodeType == snFunction )
  383. {
  384. node->DisconnectParent();
  385. RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType);
  386. }
  387. node = next;
  388. }
  389. // Make sure the default factory & constructor exists for classes
  390. if( decl->objType->beh.construct == engine->scriptTypeBehaviours.beh.construct )
  391. {
  392. AddDefaultConstructor(decl->objType, decl->script);
  393. }
  394. }
  395. // Find other global nodes
  396. for( n = 0; n < scripts.GetLength(); n++ )
  397. {
  398. // Find other global nodes
  399. asCScriptNode *node = parsers[n]->GetScriptNode();
  400. node = node->firstChild;
  401. while( node )
  402. {
  403. asCScriptNode *next = node->next;
  404. node->DisconnectParent();
  405. if( node->nodeType == snFunction )
  406. {
  407. RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, scripts[n], 0, false, true);
  408. }
  409. else if( node->nodeType == snGlobalVar )
  410. {
  411. RegisterGlobalVar(node, scripts[n]);
  412. }
  413. else if( node->nodeType == snImport )
  414. {
  415. RegisterImportedFunction(module->GetNextImportedFunctionId(), node, scripts[n]);
  416. }
  417. else
  418. {
  419. // Unused script node
  420. int r, c;
  421. scripts[n]->ConvertPosToRowCol(node->tokenPos, &r, &c);
  422. WriteWarning(scripts[n]->name.AddressOf(), TXT_UNUSED_SCRIPT_NODE, r, c);
  423. node->Destroy(engine);
  424. }
  425. node = next;
  426. }
  427. }
  428. }
  429. for( n = 0; n < parsers.GetLength(); n++ )
  430. {
  431. asDELETE(parsers[n],asCParser);
  432. }
  433. }
  434. void asCBuilder::CompileFunctions()
  435. {
  436. // Compile each function
  437. for( asUINT n = 0; n < functions.GetLength(); n++ )
  438. {
  439. if( functions[n] == 0 ) continue;
  440. asCCompiler compiler(engine);
  441. asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
  442. if( functions[n]->node )
  443. {
  444. int r, c;
  445. functions[n]->script->ConvertPosToRowCol(functions[n]->node->tokenPos, &r, &c);
  446. asCString str = func->GetDeclarationStr();
  447. str.Format(TXT_COMPILING_s, str.AddressOf());
  448. WriteInfo(functions[n]->script->name.AddressOf(), str.AddressOf(), r, c, true);
  449. compiler.CompileFunction(this, functions[n]->script, functions[n]->node, func);
  450. preMessage.isSet = false;
  451. }
  452. else
  453. {
  454. // This is the default constructor, that is generated
  455. // automatically if not implemented by the user.
  456. asASSERT( functions[n]->name == functions[n]->objType->name );
  457. compiler.CompileDefaultConstructor(this, functions[n]->script, func);
  458. }
  459. }
  460. }
  461. int asCBuilder::ParseDataType(const char *datatype, asCDataType *result)
  462. {
  463. numErrors = 0;
  464. numWarnings = 0;
  465. preMessage.isSet = false;
  466. asCScriptCode source;
  467. source.SetCode("", datatype, true);
  468. asCParser parser(this);
  469. int r = parser.ParseDataType(&source);
  470. if( r < 0 )
  471. return asINVALID_TYPE;
  472. // Get data type and property name
  473. asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
  474. *result = CreateDataTypeFromNode(dataType, &source, true);
  475. if( numErrors > 0 )
  476. return asINVALID_TYPE;
  477. return asSUCCESS;
  478. }
  479. int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCString *subtypeName)
  480. {
  481. numErrors = 0;
  482. numWarnings = 0;
  483. preMessage.isSet = false;
  484. asCScriptCode source;
  485. source.SetCode("", decl, true);
  486. asCParser parser(this);
  487. int r = parser.ParseTemplateDecl(&source);
  488. if( r < 0 )
  489. return asINVALID_TYPE;
  490. // Get the template name and subtype name
  491. asCScriptNode *node = parser.GetScriptNode()->firstChild;
  492. name->Assign(&decl[node->tokenPos], node->tokenLength);
  493. node = node->next;
  494. subtypeName->Assign(&decl[node->tokenPos], node->tokenLength);
  495. // TODO: template: check for name conflicts
  496. if( numErrors > 0 )
  497. return asINVALID_DECLARATION;
  498. return asSUCCESS;
  499. }
  500. int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &name, asCDataType &type)
  501. {
  502. numErrors = 0;
  503. numWarnings = 0;
  504. preMessage.isSet = false;
  505. if( dt )
  506. {
  507. // Verify that the object type exist
  508. if( dt->GetObjectType() == 0 )
  509. return asINVALID_OBJECT;
  510. }
  511. // Check property declaration and type
  512. asCScriptCode source;
  513. source.SetCode(TXT_PROPERTY, decl, true);
  514. asCParser parser(this);
  515. int r = parser.ParsePropertyDeclaration(&source);
  516. if( r < 0 )
  517. return asINVALID_DECLARATION;
  518. // Get data type and property name
  519. asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
  520. asCScriptNode *nameNode = dataType->next;
  521. type = CreateDataTypeFromNode(dataType, &source);
  522. name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
  523. // Validate that the type really can be a registered property
  524. // We cannot use CanBeInstanciated, as it is allowed to register
  525. // properties of type that cannot otherwise be instanciated
  526. if( type.GetFuncDef() && !type.IsObjectHandle() )
  527. {
  528. // Function definitions must always be handles
  529. return asINVALID_DECLARATION;
  530. }
  531. // Verify property name
  532. if( dt )
  533. {
  534. if( CheckNameConflictMember(dt->GetObjectType(), name.AddressOf(), nameNode, &source, true) < 0 )
  535. return asNAME_TAKEN;
  536. }
  537. else
  538. {
  539. if( CheckNameConflict(name.AddressOf(), nameNode, &source) < 0 )
  540. return asNAME_TAKEN;
  541. }
  542. if( numErrors > 0 )
  543. return asINVALID_DECLARATION;
  544. return asSUCCESS;
  545. }
  546. asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop)
  547. {
  548. asASSERT(obj.GetObjectType() != 0);
  549. // TODO: Only search in config groups to which the module has access
  550. // TODO: optimize: Improve linear search
  551. asCArray<asCObjectProperty *> &props = obj.GetObjectType()->properties;
  552. for( asUINT n = 0; n < props.GetLength(); n++ )
  553. if( props[n]->name == prop )
  554. return props[n];
  555. return 0;
  556. }
  557. asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue)
  558. {
  559. asUINT n;
  560. if( isCompiled ) *isCompiled = true;
  561. if( isPureConstant ) *isPureConstant = false;
  562. // TODO: optimize: Improve linear search
  563. // Check application registered properties
  564. asCArray<asCGlobalProperty *> *props = &(engine->registeredGlobalProps);
  565. for( n = 0; n < props->GetLength(); ++n )
  566. if( (*props)[n] && (*props)[n]->name == prop )
  567. {
  568. if( module )
  569. {
  570. // Find the config group for the global property
  571. asCConfigGroup *group = engine->FindConfigGroupForGlobalVar((*props)[n]->id);
  572. if( !group || group->HasModuleAccess(module->name.AddressOf()) )
  573. return (*props)[n];
  574. }
  575. else
  576. {
  577. // We're not compiling a module right now, so it must be a registered global property
  578. return (*props)[n];
  579. }
  580. }
  581. // TODO: optimize: Improve linear search
  582. // Check properties being compiled now
  583. asCArray<sGlobalVariableDescription *> *gvars = &globVariables;
  584. for( n = 0; n < gvars->GetLength(); ++n )
  585. {
  586. if( (*gvars)[n] && (*gvars)[n]->name == prop )
  587. {
  588. if( isCompiled ) *isCompiled = (*gvars)[n]->isCompiled;
  589. if( isPureConstant ) *isPureConstant = (*gvars)[n]->isPureConstant;
  590. if( constantValue ) *constantValue = (*gvars)[n]->constantValue;
  591. return (*gvars)[n]->property;
  592. }
  593. }
  594. // TODO: optimize: Improve linear search
  595. // Check previously compiled global variables
  596. if( module )
  597. {
  598. props = &module->scriptGlobals;
  599. for( n = 0; n < props->GetLength(); ++n )
  600. if( (*props)[n]->name == prop )
  601. return (*props)[n];
  602. }
  603. return 0;
  604. }
  605. int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray<bool> *paramAutoHandles, bool *returnAutoHandle)
  606. {
  607. // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function?
  608. numErrors = 0;
  609. numWarnings = 0;
  610. preMessage.isSet = false;
  611. asCScriptCode source;
  612. source.SetCode(TXT_SYSTEM_FUNCTION, decl, true);
  613. asCParser parser(this);
  614. int r = parser.ParseFunctionDefinition(&source);
  615. if( r < 0 )
  616. return asINVALID_DECLARATION;
  617. asCScriptNode *node = parser.GetScriptNode();
  618. // Find name
  619. asCScriptNode *n = node->firstChild->next->next;
  620. func->name.Assign(&source.code[n->tokenPos], n->tokenLength);
  621. // Initialize a script function object for registration
  622. bool autoHandle;
  623. // Scoped reference types are allowed to use handle when returned from application functions
  624. func->returnType = CreateDataTypeFromNode(node->firstChild, &source, true, objType);
  625. func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle);
  626. if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) )
  627. return asINVALID_DECLARATION;
  628. if( returnAutoHandle ) *returnAutoHandle = autoHandle;
  629. // Reference types cannot be returned by value from system functions
  630. if( isSystemFunction &&
  631. (func->returnType.GetObjectType() &&
  632. (func->returnType.GetObjectType()->flags & asOBJ_REF)) &&
  633. !(func->returnType.IsReference() ||
  634. func->returnType.IsObjectHandle()) )
  635. return asINVALID_DECLARATION;
  636. // Count number of parameters
  637. int paramCount = 0;
  638. n = n->next->firstChild;
  639. while( n )
  640. {
  641. paramCount++;
  642. n = n->next->next;
  643. if( n && n->nodeType == snIdentifier )
  644. n = n->next;
  645. if( n && n->nodeType == snExpression )
  646. n = n->next;
  647. }
  648. // Preallocate memory
  649. func->parameterTypes.Allocate(paramCount, false);
  650. func->inOutFlags.Allocate(paramCount, false);
  651. func->defaultArgs.Allocate(paramCount, false);
  652. if( paramAutoHandles ) paramAutoHandles->Allocate(paramCount, false);
  653. n = node->firstChild->next->next->next->firstChild;
  654. while( n )
  655. {
  656. asETypeModifiers inOutFlags;
  657. asCDataType type = CreateDataTypeFromNode(n, &source, false, objType);
  658. type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle);
  659. // Reference types cannot be passed by value to system functions
  660. if( isSystemFunction &&
  661. (type.GetObjectType() &&
  662. (type.GetObjectType()->flags & asOBJ_REF)) &&
  663. !(type.IsReference() ||
  664. type.IsObjectHandle()) )
  665. return asINVALID_DECLARATION;
  666. // Store the parameter type
  667. func->parameterTypes.PushLast(type);
  668. func->inOutFlags.PushLast(inOutFlags);
  669. // Don't permit void parameters
  670. if( type.GetTokenType() == ttVoid )
  671. return asINVALID_DECLARATION;
  672. if( autoHandle && (!type.IsObjectHandle() || type.IsReference()) )
  673. return asINVALID_DECLARATION;
  674. if( paramAutoHandles ) paramAutoHandles->PushLast(autoHandle);
  675. // Make sure that var type parameters are references
  676. if( type.GetTokenType() == ttQuestion &&
  677. !type.IsReference() )
  678. return asINVALID_DECLARATION;
  679. // Move to next parameter
  680. n = n->next->next;
  681. if( n && n->nodeType == snIdentifier )
  682. n = n->next;
  683. if( n && n->nodeType == snExpression )
  684. {
  685. // Strip out white space and comments to better share the string
  686. asCString *defaultArgStr = asNEW(asCString);
  687. *defaultArgStr = GetCleanExpressionString(n, &source);
  688. func->defaultArgs.PushLast(defaultArgStr);
  689. n = n->next;
  690. }
  691. else
  692. func->defaultArgs.PushLast(0);
  693. }
  694. // Set the read-only flag if const is declared after parameter list
  695. if( node->lastChild->nodeType == snUndefined && node->lastChild->tokenType == ttConst )
  696. {
  697. if( objType == 0 )
  698. return asINVALID_DECLARATION;
  699. func->isReadOnly = true;
  700. }
  701. else
  702. func->isReadOnly = false;
  703. // Make sure the default args are declared correctly
  704. ValidateDefaultArgs(&source, node, func);
  705. if( numErrors > 0 || numWarnings > 0 )
  706. return asINVALID_DECLARATION;
  707. return 0;
  708. }
  709. int asCBuilder::ParseVariableDeclaration(const char *decl, asCObjectProperty *var)
  710. {
  711. numErrors = 0;
  712. numWarnings = 0;
  713. preMessage.isSet = false;
  714. asCScriptCode source;
  715. source.SetCode(TXT_VARIABLE_DECL, decl, true);
  716. asCParser parser(this);
  717. int r = parser.ParsePropertyDeclaration(&source);
  718. if( r < 0 )
  719. return asINVALID_DECLARATION;
  720. asCScriptNode *node = parser.GetScriptNode();
  721. // Find name
  722. asCScriptNode *n = node->firstChild->next;
  723. var->name.Assign(&source.code[n->tokenPos], n->tokenLength);
  724. // Initialize a script variable object for registration
  725. var->type = CreateDataTypeFromNode(node->firstChild, &source);
  726. if( numErrors > 0 || numWarnings > 0 )
  727. return asINVALID_DECLARATION;
  728. return 0;
  729. }
  730. int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty)
  731. {
  732. // It's not necessary to check against object types
  733. // TODO: optimize: Improve linear search
  734. asCArray<asCObjectProperty *> &props = t->properties;
  735. for( asUINT n = 0; n < props.GetLength(); n++ )
  736. {
  737. if( props[n]->name == name )
  738. {
  739. if( code )
  740. {
  741. int r, c;
  742. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  743. asCString str;
  744. str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name);
  745. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  746. }
  747. return -1;
  748. }
  749. }
  750. // Property names must be checked against method names
  751. if( isProperty )
  752. {
  753. asCArray<int> methods = t->methods;
  754. for( asUINT n = 0; n < methods.GetLength(); n++ )
  755. {
  756. if( engine->scriptFunctions[methods[n]]->name == name )
  757. {
  758. if( code )
  759. {
  760. int r, c;
  761. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  762. asCString str;
  763. str.Format(TXT_NAME_CONFLICT_s_METHOD, name);
  764. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  765. }
  766. return -1;
  767. }
  768. }
  769. }
  770. return 0;
  771. }
  772. int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code)
  773. {
  774. // TODO: Must verify object types in all config groups, whether the module has access or not
  775. // Check against object types
  776. if( engine->GetObjectType(name) != 0 )
  777. {
  778. if( code )
  779. {
  780. int r, c;
  781. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  782. asCString str;
  783. str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, name);
  784. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  785. }
  786. return -1;
  787. }
  788. // TODO: Must verify global properties in all config groups, whether the module has access or not
  789. // Check against global properties
  790. asCGlobalProperty *prop = GetGlobalProperty(name, 0, 0, 0);
  791. if( prop )
  792. {
  793. if( code )
  794. {
  795. int r, c;
  796. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  797. asCString str;
  798. str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, name);
  799. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  800. }
  801. return -1;
  802. }
  803. // TODO: Property names must be checked against function names
  804. // Check against class types
  805. asUINT n;
  806. for( n = 0; n < classDeclarations.GetLength(); n++ )
  807. {
  808. if( classDeclarations[n]->name == name )
  809. {
  810. if( code )
  811. {
  812. int r, c;
  813. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  814. asCString str;
  815. str.Format(TXT_NAME_CONFLICT_s_STRUCT, name);
  816. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  817. }
  818. return -1;
  819. }
  820. }
  821. // Check against named types
  822. for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
  823. {
  824. if( namedTypeDeclarations[n]->name == name )
  825. {
  826. if( code )
  827. {
  828. int r, c;
  829. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  830. asCString str;
  831. str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, name);
  832. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  833. }
  834. return -1;
  835. }
  836. }
  837. // Must check for name conflicts with funcdefs
  838. for( n = 0; n < funcDefs.GetLength(); n++ )
  839. {
  840. if( funcDefs[n]->name == name )
  841. {
  842. if( code )
  843. {
  844. int r, c;
  845. code->ConvertPosToRowCol(node->tokenPos, &r, &c);
  846. asCString str;
  847. str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name);
  848. WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
  849. }
  850. return -1;
  851. }
  852. }
  853. return 0;
  854. }
  855. int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file)
  856. {
  857. // Find the name
  858. asASSERT( node->firstChild->nodeType == snDataType );
  859. asCScriptNode *n = node->firstChild->next->next;
  860. asCString name;
  861. name.Assign(&file->code[n->tokenPos], n->tokenLength);
  862. // Check for name conflict with other types
  863. int r = CheckNameConflict(name.AddressOf(), node, file);
  864. if( asSUCCESS != r )
  865. {
  866. node->Destroy(engine);
  867. return r;
  868. }
  869. // The function definition should be stored as a asCScriptFunction so that the application
  870. // can use the asIScriptFunction interface to enumerate the return type and parameters
  871. // The return type and parameter types aren't determined in this function. A second pass is
  872. // necessary after all type declarations have been identified.
  873. sFuncDef *fd = asNEW(sFuncDef);
  874. fd->name = name;
  875. fd->node = node;
  876. fd->script = file;
  877. fd->idx = module->AddFuncDef(name.AddressOf());
  878. funcDefs.PushLast(fd);
  879. return 0;
  880. }
  881. void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
  882. {
  883. asCDataType returnType;
  884. asCArray<asCDataType> parameterTypes;
  885. asCArray<asETypeModifiers> inOutFlags;
  886. asCArray<asCString *> defaultArgs;
  887. bool isConstMethod;
  888. bool isConstructor;
  889. bool isDestructor;
  890. bool isPrivate;
  891. GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, returnType, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate);
  892. asCScriptFunction *func = module->funcDefs[funcDef->idx];
  893. if( func )
  894. {
  895. func->returnType = returnType;
  896. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  897. {
  898. func->parameterTypes.PushLast(parameterTypes[p]);
  899. func->inOutFlags.PushLast(inOutFlags[p]);
  900. // Don't copy the default arg expression as it is not allowed for function definitions
  901. }
  902. }
  903. }
  904. int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file)
  905. {
  906. // What data type is it?
  907. asCDataType type = CreateDataTypeFromNode(node->firstChild, file);
  908. if( !type.CanBeInstanciated() )
  909. {
  910. asCString str;
  911. // TODO: Change to "'type' cannot be declared as variable"
  912. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  913. int r, c;
  914. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  915. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  916. }
  917. asCScriptNode *n = node->firstChild->next;
  918. while( n )
  919. {
  920. // Verify that the name isn't taken
  921. asCString name(&file->code[n->tokenPos], n->tokenLength);
  922. CheckNameConflict(name.AddressOf(), n, file);
  923. // Register the global variable
  924. sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
  925. globVariables.PushLast(gvar);
  926. gvar->script = file;
  927. gvar->name = name;
  928. gvar->isCompiled = false;
  929. gvar->datatype = type;
  930. gvar->isEnumValue = false;
  931. // TODO: Give error message if wrong
  932. asASSERT(!gvar->datatype.IsReference());
  933. gvar->idNode = n;
  934. gvar->nextNode = 0;
  935. if( n->next &&
  936. (n->next->nodeType == snAssignment ||
  937. n->next->nodeType == snArgList ||
  938. n->next->nodeType == snInitList ) )
  939. {
  940. gvar->nextNode = n->next;
  941. n->next->DisconnectParent();
  942. }
  943. gvar->property = module->AllocateGlobalProperty(name.AddressOf(), gvar->datatype);
  944. gvar->index = gvar->property->id;
  945. n = n->next;
  946. }
  947. node->Destroy(engine);
  948. return 0;
  949. }
  950. int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file)
  951. {
  952. asCScriptNode *n = node->firstChild;
  953. asCString name(&file->code[n->tokenPos], n->tokenLength);
  954. int r, c;
  955. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  956. CheckNameConflict(name.AddressOf(), n, file);
  957. sClassDeclaration *decl = asNEW(sClassDeclaration);
  958. classDeclarations.PushLast(decl);
  959. decl->name = name;
  960. decl->script = file;
  961. decl->validState = 0;
  962. decl->node = node;
  963. asCObjectType *st = asNEW(asCObjectType)(engine);
  964. st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
  965. if( node->tokenType == ttHandle )
  966. st->flags |= asOBJ_IMPLICIT_HANDLE;
  967. st->size = sizeof(asCScriptObject);
  968. st->name = name;
  969. module->classTypes.PushLast(st);
  970. engine->classTypes.PushLast(st);
  971. st->AddRef();
  972. decl->objType = st;
  973. // Add script classes to the GC
  974. engine->gc.AddScriptObjectToGC(st, &engine->objectTypeBehaviours);
  975. // Use the default script class behaviours
  976. st->beh = engine->scriptTypeBehaviours.beh;
  977. // TODO: Move this to asCObjectType so that the asCRestore can reuse it
  978. engine->scriptFunctions[st->beh.addref]->AddRef();
  979. engine->scriptFunctions[st->beh.release]->AddRef();
  980. engine->scriptFunctions[st->beh.gcEnumReferences]->AddRef();
  981. engine->scriptFunctions[st->beh.gcGetFlag]->AddRef();
  982. engine->scriptFunctions[st->beh.gcGetRefCount]->AddRef();
  983. engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRef();
  984. engine->scriptFunctions[st->beh.gcSetFlag]->AddRef();
  985. engine->scriptFunctions[st->beh.copy]->AddRef();
  986. engine->scriptFunctions[st->beh.factory]->AddRef();
  987. engine->scriptFunctions[st->beh.construct]->AddRef();
  988. for( asUINT i = 1; i < st->beh.operators.GetLength(); i += 2 )
  989. engine->scriptFunctions[st->beh.operators[i]]->AddRef();
  990. return 0;
  991. }
  992. int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file)
  993. {
  994. asCScriptNode *n = node->firstChild;
  995. asCString name(&file->code[n->tokenPos], n->tokenLength);
  996. int r, c;
  997. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  998. CheckNameConflict(name.AddressOf(), n, file);
  999. sClassDeclaration *decl = asNEW(sClassDeclaration);
  1000. interfaceDeclarations.PushLast(decl);
  1001. decl->name = name;
  1002. decl->script = file;
  1003. decl->validState = 0;
  1004. decl->node = node;
  1005. // Register the object type for the interface
  1006. asCObjectType *st = asNEW(asCObjectType)(engine);
  1007. st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
  1008. st->size = 0; // Cannot be instanciated
  1009. st->name = name;
  1010. module->classTypes.PushLast(st);
  1011. engine->classTypes.PushLast(st);
  1012. st->AddRef();
  1013. decl->objType = st;
  1014. // Use the default script class behaviours
  1015. st->beh.construct = 0;
  1016. st->beh.addref = engine->scriptTypeBehaviours.beh.addref;
  1017. engine->scriptFunctions[st->beh.addref]->AddRef();
  1018. st->beh.release = engine->scriptTypeBehaviours.beh.release;
  1019. engine->scriptFunctions[st->beh.release]->AddRef();
  1020. st->beh.copy = 0;
  1021. return 0;
  1022. }
  1023. void asCBuilder::CompileGlobalVariables()
  1024. {
  1025. bool compileSucceeded = true;
  1026. // Store state of compilation (errors, warning, output)
  1027. int currNumErrors = numErrors;
  1028. int currNumWarnings = numWarnings;
  1029. // Backup the original message stream
  1030. bool msgCallback = engine->msgCallback;
  1031. asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc;
  1032. void *msgCallbackObj = engine->msgCallbackObj;
  1033. // Set the new temporary message stream
  1034. asCOutputBuffer outBuffer;
  1035. engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL);
  1036. asCOutputBuffer finalOutput;
  1037. asCScriptFunction *initFunc = 0;
  1038. asCArray<asCGlobalProperty*> initOrder;
  1039. // We first try to compile all the primitive global variables, and only after that
  1040. // compile the non-primitive global variables. This permits the constructors
  1041. // for the complex types to use the already initialized variables of primitive
  1042. // type. Note, we currently don't know which global variables are used in the
  1043. // constructors, so we cannot guarantee that variables of complex types are
  1044. // initialized in the correct order, so we won't reorder those.
  1045. bool compilingPrimitives = true;
  1046. // Compile each global variable
  1047. while( compileSucceeded )
  1048. {
  1049. compileSucceeded = false;
  1050. int accumErrors = 0;
  1051. int accumWarnings = 0;
  1052. // Restore state of compilation
  1053. finalOutput.Clear();
  1054. for( asUINT n = 0; n < globVariables.GetLength(); n++ )
  1055. {
  1056. sGlobalVariableDescription *gvar = globVariables[n];
  1057. if( gvar->isCompiled )
  1058. continue;
  1059. asCByteCode init(engine);
  1060. numWarnings = 0;
  1061. numErrors = 0;
  1062. outBuffer.Clear();
  1063. // Skip this for now if we're not compiling complex types yet
  1064. if( compilingPrimitives && !gvar->datatype.IsPrimitive() )
  1065. continue;
  1066. if( gvar->nextNode )
  1067. {
  1068. int r, c;
  1069. gvar->script->ConvertPosToRowCol(gvar->nextNode->tokenPos, &r, &c);
  1070. asCString str = gvar->datatype.Format();
  1071. str += " " + gvar->name;
  1072. str.Format(TXT_COMPILING_s, str.AddressOf());
  1073. WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), r, c, true);
  1074. }
  1075. if( gvar->isEnumValue )
  1076. {
  1077. int r;
  1078. if( gvar->nextNode )
  1079. {
  1080. asCCompiler comp(engine);
  1081. asCScriptFunction func(engine, module, asFUNC_DUMMY);
  1082. // Temporarily switch the type of the variable to int so it can be compiled properly
  1083. asCDataType saveType;
  1084. saveType = gvar->datatype;
  1085. gvar->datatype = asCDataType::CreatePrimitive(ttInt, true);
  1086. r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar, &func);
  1087. gvar->datatype = saveType;
  1088. }
  1089. else
  1090. {
  1091. r = 0;
  1092. // When there is no assignment the value is the last + 1
  1093. int enumVal = 0;
  1094. if( n > 0 )
  1095. {
  1096. sGlobalVariableDescription *gvar2 = globVariables[n-1];
  1097. if( gvar2->datatype == gvar->datatype )
  1098. {
  1099. // The integer value is stored in the lower bytes
  1100. enumVal = (*(int*)&gvar2->constantValue) + 1;
  1101. if( !gvar2->isCompiled )
  1102. {
  1103. // TODO: Need to get the correct script position
  1104. int row, col;
  1105. gvar->script->ConvertPosToRowCol(0, &row, &col);
  1106. asCString str = gvar->datatype.Format();
  1107. str += " " + gvar->name;
  1108. str.Format(TXT_COMPILING_s, str.AddressOf());
  1109. WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), row, col, true);
  1110. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, gvar2->name.AddressOf());
  1111. WriteError(gvar->script->name.AddressOf(), str.AddressOf(), row, col);
  1112. r = -1;
  1113. }
  1114. }
  1115. }
  1116. // The integer value is stored in the lower bytes
  1117. *(int*)&gvar->constantValue = enumVal;
  1118. }
  1119. if( r >= 0 )
  1120. {
  1121. // Set the value as compiled
  1122. gvar->isCompiled = true;
  1123. compileSucceeded = true;
  1124. }
  1125. }
  1126. else
  1127. {
  1128. // Compile the global variable
  1129. initFunc = asNEW(asCScriptFunction)(engine, module, asFUNC_DUMMY);
  1130. asCCompiler comp(engine);
  1131. int r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar, initFunc);
  1132. if( r >= 0 )
  1133. {
  1134. // Compilation succeeded
  1135. gvar->isCompiled = true;
  1136. compileSucceeded = true;
  1137. }
  1138. else
  1139. {
  1140. // Compilation failed
  1141. asDELETE(initFunc, asCScriptFunction);
  1142. initFunc = 0;
  1143. }
  1144. }
  1145. if( gvar->isCompiled )
  1146. {
  1147. // Add warnings for this constant to the total build
  1148. if( numWarnings )
  1149. {
  1150. currNumWarnings += numWarnings;
  1151. if( msgCallback )
  1152. outBuffer.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
  1153. }
  1154. // Determine order of variable initializations
  1155. if( gvar->property && !gvar->isEnumValue )
  1156. initOrder.PushLast(gvar->property);
  1157. // Does the function contain more than just a SUSPEND followed by a RET instruction?
  1158. if( initFunc && initFunc->byteCode.GetLength() > 2 )
  1159. {
  1160. // Create the init function for this variable
  1161. initFunc->id = engine->GetNextScriptFunctionId();
  1162. engine->SetScriptFunction(initFunc);
  1163. // Finalize the init function for this variable
  1164. initFunc->funcType = asFUNC_SCRIPT;
  1165. initFunc->returnType = asCDataType::CreatePrimitive(ttVoid, false);
  1166. initFunc->scriptSectionIdx = engine->GetScriptSectionNameIndex(gvar->script->name.AddressOf());
  1167. // Notify the GC of the new script function
  1168. engine->gc.AddScriptObjectToGC(initFunc, &engine->functionBehaviours);
  1169. gvar->property->SetInitFunc(initFunc);
  1170. initFunc->Release();
  1171. initFunc = 0;
  1172. }
  1173. else if( initFunc )
  1174. {
  1175. // Destroy the function as it won't be used
  1176. asDELETE(initFunc, asCScriptFunction);
  1177. initFunc = 0;
  1178. }
  1179. // Convert enums to true enum values, so subsequent compilations can access it as an enum
  1180. if( gvar->isEnumValue )
  1181. {
  1182. asCObjectType *objectType = gvar->datatype.GetObjectType();
  1183. asASSERT(NULL != objectType);
  1184. asSEnumValue *e = asNEW(asSEnumValue);
  1185. e->name = gvar->name;
  1186. e->value = *(int*)&gvar->constantValue;
  1187. objectType->enumValues.PushLast(e);
  1188. }
  1189. }
  1190. else
  1191. {
  1192. // Add output to final output
  1193. finalOutput.Append(outBuffer);
  1194. accumErrors += numErrors;
  1195. accumWarnings += numWarnings;
  1196. }
  1197. preMessage.isSet = false;
  1198. }
  1199. if( !compileSucceeded )
  1200. {
  1201. if( compilingPrimitives )
  1202. {
  1203. // No more primitives could be compiled, so
  1204. // switch to compiling the complex variables
  1205. compilingPrimitives = false;
  1206. compileSucceeded = true;
  1207. }
  1208. else
  1209. {
  1210. // No more variables can be compiled
  1211. // Add errors and warnings to total build
  1212. currNumWarnings += accumWarnings;
  1213. currNumErrors += accumErrors;
  1214. if( msgCallback )
  1215. finalOutput.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
  1216. }
  1217. }
  1218. }
  1219. // Restore states
  1220. engine->msgCallback = msgCallback;
  1221. engine->msgCallbackFunc = msgCallbackFunc;
  1222. engine->msgCallbackObj = msgCallbackObj;
  1223. numWarnings = currNumWarnings;
  1224. numErrors = currNumErrors;
  1225. // Set the correct order of initialization
  1226. if( numErrors == 0 )
  1227. {
  1228. // If the length of the arrays are not the same, then this is the compilation
  1229. // of a single variable, in which case the initialization order of the previous
  1230. // variables must be preserved.
  1231. if( module->scriptGlobals.GetLength() == initOrder.GetLength() )
  1232. module->scriptGlobals = initOrder;
  1233. }
  1234. // Delete the enum expressions
  1235. for( asUINT n = 0; n < globVariables.GetLength(); n++ )
  1236. {
  1237. sGlobalVariableDescription *gvar = globVariables[n];
  1238. if( gvar->isEnumValue )
  1239. {
  1240. // Destroy the gvar property
  1241. if( gvar->nextNode )
  1242. {
  1243. gvar->nextNode->Destroy(engine);
  1244. gvar->nextNode = 0;
  1245. }
  1246. if( gvar->property )
  1247. {
  1248. asDELETE(gvar->property, asCGlobalProperty);
  1249. gvar->property = 0;
  1250. }
  1251. asDELETE(gvar, sGlobalVariableDescription);
  1252. globVariables[n] = 0;
  1253. }
  1254. }
  1255. }
  1256. void asCBuilder::CompileClasses()
  1257. {
  1258. asUINT n;
  1259. asCArray<sClassDeclaration*> toValidate((int)classDeclarations.GetLength());
  1260. // Determine class inheritances and interfaces
  1261. for( n = 0; n < classDeclarations.GetLength(); n++ )
  1262. {
  1263. sClassDeclaration *decl = classDeclarations[n];
  1264. asCScriptCode *file = decl->script;
  1265. // Find the base class that this class inherits from
  1266. bool multipleInheritance = false;
  1267. asCScriptNode *node = decl->node->firstChild->next;
  1268. while( node && node->nodeType == snIdentifier )
  1269. {
  1270. // Get the interface name from the node
  1271. asCString name(&file->code[node->tokenPos], node->tokenLength);
  1272. // Find the object type for the interface
  1273. asCObjectType *objType = GetObjectType(name.AddressOf());
  1274. if( objType == 0 )
  1275. {
  1276. int r, c;
  1277. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1278. asCString str;
  1279. str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, name.AddressOf());
  1280. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  1281. }
  1282. else if( !(objType->flags & asOBJ_SCRIPT_OBJECT) )
  1283. {
  1284. int r, c;
  1285. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1286. asCString str;
  1287. str.Format(TXT_CANNOT_INHERIT_FROM_s, objType->name.AddressOf());
  1288. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  1289. }
  1290. else if( objType->size != 0 )
  1291. {
  1292. // The class inherits from another script class
  1293. if( decl->objType->derivedFrom != 0 )
  1294. {
  1295. if( !multipleInheritance )
  1296. {
  1297. int r, c;
  1298. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1299. WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, r, c);
  1300. multipleInheritance = true;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. // Make sure none of the base classes inherit from this one
  1306. asCObjectType *base = objType;
  1307. bool error = false;
  1308. while( base != 0 )
  1309. {
  1310. if( base == decl->objType )
  1311. {
  1312. int r, c;
  1313. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1314. WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_SELF, r, c);
  1315. error = true;
  1316. break;
  1317. }
  1318. base = base->derivedFrom;
  1319. }
  1320. if( !error )
  1321. {
  1322. decl->objType->derivedFrom = objType;
  1323. objType->AddRef();
  1324. }
  1325. }
  1326. }
  1327. else
  1328. {
  1329. // The class implements an interface
  1330. if( decl->objType->Implements(objType) )
  1331. {
  1332. int r, c;
  1333. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1334. asCString msg;
  1335. msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, objType->GetName());
  1336. WriteWarning(file->name.AddressOf(), msg.AddressOf(), r, c);
  1337. }
  1338. else
  1339. {
  1340. decl->objType->interfaces.PushLast(objType);
  1341. }
  1342. }
  1343. node = node->next;
  1344. }
  1345. }
  1346. // Order class declarations so that base classes are compiled before derived classes.
  1347. // This will allow the derived classes to copy properties and methods in the next step.
  1348. for( n = 0; n < classDeclarations.GetLength(); n++ )
  1349. {
  1350. sClassDeclaration *decl = classDeclarations[n];
  1351. asCObjectType *derived = decl->objType;
  1352. asCObjectType *base = derived->derivedFrom;
  1353. if( base == 0 ) continue;
  1354. // If the base class is found after the derived class, then move the derived class to the end of the list
  1355. for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ )
  1356. {
  1357. sClassDeclaration *declBase = classDeclarations[m];
  1358. if( base == declBase->objType )
  1359. {
  1360. classDeclarations.RemoveIndex(n);
  1361. classDeclarations.PushLast(decl);
  1362. // Decrease index so that we don't skip an entry
  1363. n--;
  1364. break;
  1365. }
  1366. }
  1367. }
  1368. // Go through each of the classes and register the object type descriptions
  1369. for( n = 0; n < classDeclarations.GetLength(); n++ )
  1370. {
  1371. sClassDeclaration *decl = classDeclarations[n];
  1372. // Add all properties and methods from the base class
  1373. if( decl->objType->derivedFrom )
  1374. {
  1375. asCObjectType *baseType = decl->objType->derivedFrom;
  1376. // The derived class inherits all interfaces from the base class
  1377. for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ )
  1378. {
  1379. if( !decl->objType->Implements(baseType->interfaces[n]) )
  1380. {
  1381. decl->objType->interfaces.PushLast(baseType->interfaces[n]);
  1382. }
  1383. else
  1384. {
  1385. // Warn if derived class already implements the interface
  1386. int r, c;
  1387. decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
  1388. asCString msg;
  1389. msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, baseType->interfaces[n]->GetName());
  1390. WriteWarning(decl->script->name.AddressOf(), msg.AddressOf(), r, c);
  1391. }
  1392. }
  1393. // TODO: Need to check for name conflict with new class methods
  1394. // Copy properties from base class to derived class
  1395. for( asUINT p = 0; p < baseType->properties.GetLength(); p++ )
  1396. {
  1397. asCObjectProperty *prop = AddPropertyToClass(decl, baseType->properties[p]->name, baseType->properties[p]->type, baseType->properties[p]->isPrivate);
  1398. // The properties must maintain the same offset
  1399. asASSERT(prop && prop->byteOffset == baseType->properties[p]->byteOffset); UNUSED_VAR(prop);
  1400. }
  1401. // Copy methods from base class to derived class
  1402. for( asUINT m = 0; m < baseType->methods.GetLength(); m++ )
  1403. {
  1404. // If the derived class implements the same method, then don't add the base class' method
  1405. asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]);
  1406. asCScriptFunction *derivedFunc = 0;
  1407. bool found = false;
  1408. for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ )
  1409. {
  1410. derivedFunc = GetFunctionDescription(decl->objType->methods[d]);
  1411. if( derivedFunc->IsSignatureEqual(baseFunc) )
  1412. {
  1413. // Move the function from the methods array to the virtualFunctionTable
  1414. decl->objType->methods.RemoveIndex(d);
  1415. decl->objType->virtualFunctionTable.PushLast(derivedFunc);
  1416. found = true;
  1417. break;
  1418. }
  1419. }
  1420. if( !found )
  1421. {
  1422. // Push the base class function on the virtual function table
  1423. decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]);
  1424. baseType->virtualFunctionTable[m]->AddRef();
  1425. }
  1426. decl->objType->methods.PushLast(baseType->methods[m]);
  1427. engine->scriptFunctions[baseType->methods[m]]->AddRef();
  1428. }
  1429. }
  1430. // Move this class' methods into the virtual function table
  1431. for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ )
  1432. {
  1433. asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[m]);
  1434. if( func->funcType != asFUNC_VIRTUAL )
  1435. {
  1436. // Move the reference from the method list to the virtual function list
  1437. decl->objType->methods.RemoveIndex(m);
  1438. decl->objType->virtualFunctionTable.PushLast(func);
  1439. // Substitute the function description in the method list for a virtual method
  1440. // Make sure the methods are in the same order as the virtual function table
  1441. decl->objType->methods.PushLast(CreateVirtualFunction(func, (int)decl->objType->virtualFunctionTable.GetLength() - 1));
  1442. m--;
  1443. }
  1444. }
  1445. // Enumerate each of the declared properties
  1446. asCScriptNode *node = decl->node->firstChild->next;
  1447. // Skip list of classes and interfaces
  1448. while( node && node->nodeType == snIdentifier )
  1449. node = node->next;
  1450. while( node )
  1451. {
  1452. if( node->nodeType == snDeclaration )
  1453. {
  1454. bool isPrivate = false;
  1455. if( node->firstChild && node->firstChild->tokenType == ttPrivate )
  1456. isPrivate = true;
  1457. asCScriptCode *file = decl->script;
  1458. asCDataType dt = CreateDataTypeFromNode(isPrivate ? node->firstChild->next : node->firstChild, file);
  1459. asCString name(&file->code[node->lastChild->tokenPos], node->lastChild->tokenLength);
  1460. if( dt.IsReadOnly() )
  1461. {
  1462. int r, c;
  1463. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1464. WriteError(file->name.AddressOf(), TXT_PROPERTY_CANT_BE_CONST, r, c);
  1465. }
  1466. CheckNameConflictMember(decl->objType, name.AddressOf(), node->lastChild, file, true);
  1467. AddPropertyToClass(decl, name, dt, isPrivate, file, node);
  1468. }
  1469. else
  1470. asASSERT(false);
  1471. node = node->next;
  1472. }
  1473. toValidate.PushLast(decl);
  1474. }
  1475. // Verify that all interface methods are implemented in the classes
  1476. // We do this here so the base class' methods have already been inherited
  1477. for( n = 0; n < classDeclarations.GetLength(); n++ )
  1478. {
  1479. sClassDeclaration *decl = classDeclarations[n];
  1480. for( asUINT m = 0; m < decl->objType->interfaces.GetLength(); m++ )
  1481. {
  1482. asCObjectType *objType = decl->objType->interfaces[m];
  1483. for( asUINT i = 0; i < objType->methods.GetLength(); i++ )
  1484. {
  1485. if( !DoesMethodExist(decl->objType, objType->methods[i]) )
  1486. {
  1487. int r, c;
  1488. decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
  1489. asCString str;
  1490. str.Format(TXT_MISSING_IMPLEMENTATION_OF_s,
  1491. engine->GetFunctionDeclaration(objType->methods[i]).AddressOf());
  1492. WriteError(decl->script->name.AddressOf(), str.AddressOf(), r, c);
  1493. }
  1494. }
  1495. }
  1496. }
  1497. // Verify that the declared structures are valid, e.g. that the structure
  1498. // doesn't contain a member of its own type directly or indirectly
  1499. while( toValidate.GetLength() > 0 )
  1500. {
  1501. asUINT numClasses = (asUINT)toValidate.GetLength();
  1502. asCArray<sClassDeclaration*> toValidateNext((int)toValidate.GetLength());
  1503. while( toValidate.GetLength() > 0 )
  1504. {
  1505. sClassDeclaration *decl = toValidate[toValidate.GetLength()-1];
  1506. int validState = 1;
  1507. for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ )
  1508. {
  1509. // A valid structure is one that uses only primitives or other valid objects
  1510. asCObjectProperty *prop = decl->objType->properties[n];
  1511. asCDataType dt = prop->type;
  1512. if( dt.IsTemplate() )
  1513. {
  1514. asCDataType sub = dt;
  1515. while( sub.IsTemplate() && !sub.IsObjectHandle() )
  1516. sub = sub.GetSubType();
  1517. dt = sub;
  1518. }
  1519. if( dt.IsObject() && !dt.IsObjectHandle() )
  1520. {
  1521. // Find the class declaration
  1522. sClassDeclaration *pdecl = 0;
  1523. for( asUINT p = 0; p < classDeclarations.GetLength(); p++ )
  1524. {
  1525. if( classDeclarations[p]->objType == dt.GetObjectType() )
  1526. {
  1527. pdecl = classDeclarations[p];
  1528. break;
  1529. }
  1530. }
  1531. if( pdecl )
  1532. {
  1533. if( pdecl->objType == decl->objType )
  1534. {
  1535. int r, c;
  1536. decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
  1537. WriteError(decl->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
  1538. validState = 2;
  1539. break;
  1540. }
  1541. else if( pdecl->validState != 1 )
  1542. {
  1543. validState = pdecl->validState;
  1544. break;
  1545. }
  1546. }
  1547. }
  1548. }
  1549. if( validState == 1 )
  1550. {
  1551. decl->validState = 1;
  1552. toValidate.PopLast();
  1553. }
  1554. else if( validState == 2 )
  1555. {
  1556. decl->validState = 2;
  1557. toValidate.PopLast();
  1558. }
  1559. else
  1560. {
  1561. toValidateNext.PushLast(toValidate.PopLast());
  1562. }
  1563. }
  1564. toValidate = toValidateNext;
  1565. toValidateNext.SetLength(0);
  1566. if( numClasses == toValidate.GetLength() )
  1567. {
  1568. int r, c;
  1569. toValidate[0]->script->ConvertPosToRowCol(toValidate[0]->node->tokenPos, &r, &c);
  1570. WriteError(toValidate[0]->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
  1571. break;
  1572. }
  1573. }
  1574. if( numErrors > 0 ) return;
  1575. // Urho3D: disable garbage collection from script classes
  1576. /*
  1577. // Verify potential circular references
  1578. for( n = 0; n < classDeclarations.GetLength(); n++ )
  1579. {
  1580. sClassDeclaration *decl = classDeclarations[n];
  1581. asCObjectType *ot = decl->objType;
  1582. // Is there some path in which this structure is involved in circular references?
  1583. for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
  1584. {
  1585. asCDataType dt = ot->properties[p]->type;
  1586. if( dt.IsObject() )
  1587. {
  1588. if( dt.IsObjectHandle() )
  1589. {
  1590. // TODO: optimize: If it is known that the handle can't be involved in a circular reference
  1591. // then this object doesn't need to be marked as garbage collected.
  1592. // - The application could set a flag when registering the object.
  1593. // - The script classes can be marked as final, then the compiler will
  1594. // be able to determine whether the class is garbage collected or not.
  1595. ot->flags |= asOBJ_GC;
  1596. break;
  1597. }
  1598. else if( dt.GetObjectType()->flags & asOBJ_GC )
  1599. {
  1600. // TODO: optimize: Just because the member type is a potential circle doesn't mean that this one is
  1601. // Only if the object is of a type that can reference this type, either directly or indirectly
  1602. ot->flags |= asOBJ_GC;
  1603. break;
  1604. }
  1605. }
  1606. }
  1607. }
  1608. */
  1609. }
  1610. int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx)
  1611. {
  1612. asCScriptFunction *vf = asNEW(asCScriptFunction)(engine, module, asFUNC_VIRTUAL);
  1613. vf->funcType = asFUNC_VIRTUAL;
  1614. vf->name = func->name;
  1615. vf->returnType = func->returnType;
  1616. vf->parameterTypes = func->parameterTypes;
  1617. vf->inOutFlags = func->inOutFlags;
  1618. vf->id = engine->GetNextScriptFunctionId();
  1619. vf->scriptSectionIdx = func->scriptSectionIdx;
  1620. vf->isReadOnly = func->isReadOnly;
  1621. vf->objectType = func->objectType;
  1622. vf->signatureId = func->signatureId;
  1623. vf->isPrivate = func->isPrivate;
  1624. vf->vfTableIdx = idx;
  1625. vf->defaultArgs = func->defaultArgs;
  1626. // Copy the default arg strings to avoid multiple deletes on the same object
  1627. for( asUINT n = 0; n < vf->defaultArgs.GetLength(); n++ )
  1628. if( vf->defaultArgs[n] )
  1629. vf->defaultArgs[n] = asNEW(asCString)(*vf->defaultArgs[n]);
  1630. module->AddScriptFunction(vf);
  1631. // Add a dummy to the builder so that it doesn't mix up function ids
  1632. functions.PushLast(0);
  1633. return vf->id;
  1634. }
  1635. asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, bool isPrivate, asCScriptCode *file, asCScriptNode *node)
  1636. {
  1637. if( !dt.CanBeInstanciated() )
  1638. {
  1639. if( file && node )
  1640. {
  1641. int r, c;
  1642. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1643. asCString str;
  1644. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
  1645. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  1646. }
  1647. return 0;
  1648. }
  1649. return decl->objType->AddPropertyToClass(name, dt, isPrivate);
  1650. }
  1651. bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId)
  1652. {
  1653. asCScriptFunction *method = GetFunctionDescription(methodId);
  1654. for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
  1655. {
  1656. asCScriptFunction *m = GetFunctionDescription(objType->methods[n]);
  1657. if( m->name != method->name ) continue;
  1658. if( m->returnType != method->returnType ) continue;
  1659. if( m->isReadOnly != method->isReadOnly ) continue;
  1660. if( m->parameterTypes != method->parameterTypes ) continue;
  1661. if( m->inOutFlags != method->inOutFlags ) continue;
  1662. return true;
  1663. }
  1664. return false;
  1665. }
  1666. void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file)
  1667. {
  1668. int funcId = engine->GetNextScriptFunctionId();
  1669. asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false);
  1670. asCArray<asCDataType> parameterTypes;
  1671. asCArray<asETypeModifiers> inOutFlags;
  1672. asCArray<asCString *> defaultArgs;
  1673. // Add the script function
  1674. module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false, objType);
  1675. // Set it as default constructor
  1676. if( objType->beh.construct )
  1677. engine->scriptFunctions[objType->beh.construct]->Release();
  1678. objType->beh.construct = funcId;
  1679. objType->beh.constructors[0] = funcId;
  1680. engine->scriptFunctions[funcId]->AddRef();
  1681. // The bytecode for the default constructor will be generated
  1682. // only after the potential inheritance has been established
  1683. sFunctionDescription *func = asNEW(sFunctionDescription);
  1684. functions.PushLast(func);
  1685. func->script = file;
  1686. func->node = 0;
  1687. func->name = objType->name;
  1688. func->objType = objType;
  1689. func->funcId = funcId;
  1690. // Add a default factory as well
  1691. funcId = engine->GetNextScriptFunctionId();
  1692. if( objType->beh.factory )
  1693. engine->scriptFunctions[objType->beh.factory]->Release();
  1694. objType->beh.factory = funcId;
  1695. objType->beh.factories[0] = funcId;
  1696. returnType = asCDataType::CreateObjectHandle(objType, false);
  1697. module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
  1698. functions.PushLast(0);
  1699. asCCompiler compiler(engine);
  1700. compiler.CompileFactory(this, file, engine->scriptFunctions[funcId]);
  1701. engine->scriptFunctions[funcId]->AddRef();
  1702. }
  1703. int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file)
  1704. {
  1705. // Grab the name of the enumeration
  1706. asCScriptNode *tmp = node->firstChild;
  1707. asASSERT(snDataType == tmp->nodeType);
  1708. asCString name;
  1709. asASSERT(snIdentifier == tmp->firstChild->nodeType);
  1710. name.Assign(&file->code[tmp->firstChild->tokenPos], tmp->firstChild->tokenLength);
  1711. // Check the name and add the enum
  1712. int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file);
  1713. if( asSUCCESS == r )
  1714. {
  1715. asCObjectType *st;
  1716. asCDataType dataType;
  1717. st = asNEW(asCObjectType)(engine);
  1718. dataType.CreatePrimitive(ttInt, false);
  1719. st->flags = asOBJ_ENUM;
  1720. st->size = 4;
  1721. st->name = name;
  1722. module->enumTypes.PushLast(st);
  1723. st->AddRef();
  1724. engine->classTypes.PushLast(st);
  1725. // Store the location of this declaration for reference in name collisions
  1726. sClassDeclaration *decl = asNEW(sClassDeclaration);
  1727. decl->name = name;
  1728. decl->script = file;
  1729. decl->validState = 0;
  1730. decl->node = NULL;
  1731. decl->objType = st;
  1732. namedTypeDeclarations.PushLast(decl);
  1733. asCDataType type = CreateDataTypeFromNode(tmp, file);
  1734. asASSERT(!type.IsReference());
  1735. tmp = tmp->next;
  1736. while( tmp )
  1737. {
  1738. asASSERT(snIdentifier == tmp->nodeType);
  1739. asCString name(&file->code[tmp->tokenPos], tmp->tokenLength);
  1740. // Check for name conflict errors with other values in the enum
  1741. r = 0;
  1742. for( size_t n = globVariables.GetLength(); n-- > 0; )
  1743. {
  1744. sGlobalVariableDescription *gvar = globVariables[n];
  1745. if( gvar->datatype != type )
  1746. break;
  1747. if( gvar->name == name )
  1748. {
  1749. r = asNAME_TAKEN;
  1750. break;
  1751. }
  1752. }
  1753. if( asSUCCESS != r )
  1754. {
  1755. int r, c;
  1756. file->ConvertPosToRowCol(tmp->tokenPos, &r, &c);
  1757. asCString str;
  1758. str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.AddressOf());
  1759. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  1760. tmp = tmp->next;
  1761. if( tmp && tmp->nodeType == snAssignment )
  1762. tmp = tmp->next;
  1763. continue;
  1764. }
  1765. // check for assignment
  1766. asCScriptNode *asnNode = tmp->next;
  1767. if( asnNode && snAssignment == asnNode->nodeType )
  1768. asnNode->DisconnectParent();
  1769. else
  1770. asnNode = 0;
  1771. // Create the global variable description so the enum value can be evaluated
  1772. sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
  1773. globVariables.PushLast(gvar);
  1774. gvar->script = file;
  1775. gvar->idNode = 0;
  1776. gvar->nextNode = asnNode;
  1777. gvar->name = name;
  1778. gvar->datatype = type;
  1779. // No need to allocate space on the global memory stack since the values are stored in the asCObjectType
  1780. gvar->index = 0;
  1781. gvar->isCompiled = false;
  1782. gvar->isPureConstant = true;
  1783. gvar->isEnumValue = true;
  1784. gvar->constantValue = 0xdeadbeef;
  1785. // Allocate dummy property so we can compile the value.
  1786. // This will be removed later on so we don't add it to the engine.
  1787. gvar->property = asNEW(asCGlobalProperty);
  1788. gvar->property->name = name;
  1789. gvar->property->type = gvar->datatype;
  1790. gvar->property->id = 0;
  1791. tmp = tmp->next;
  1792. }
  1793. }
  1794. node->Destroy(engine);
  1795. return r;
  1796. }
  1797. int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file)
  1798. {
  1799. // Get the native data type
  1800. asCScriptNode *tmp = node->firstChild;
  1801. asASSERT(NULL != tmp && snDataType == tmp->nodeType);
  1802. asCDataType dataType;
  1803. dataType.CreatePrimitive(tmp->tokenType, false);
  1804. dataType.SetTokenType(tmp->tokenType);
  1805. tmp = tmp->next;
  1806. // Grab the name of the typedef
  1807. asASSERT(NULL != tmp && NULL == tmp->next);
  1808. asCString name;
  1809. name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength);
  1810. // If the name is not already in use add it
  1811. int r = CheckNameConflict(name.AddressOf(), tmp, file);
  1812. if( asSUCCESS == r )
  1813. {
  1814. // Create the new type
  1815. asCObjectType *st = asNEW(asCObjectType)(engine);
  1816. st->flags = asOBJ_TYPEDEF;
  1817. st->size = dataType.GetSizeInMemoryBytes();
  1818. st->name = name;
  1819. st->templateSubType = dataType;
  1820. st->AddRef();
  1821. module->typeDefs.PushLast(st);
  1822. engine->classTypes.PushLast(st);
  1823. // Store the location of this declaration for reference in name collisions
  1824. sClassDeclaration *decl = asNEW(sClassDeclaration);
  1825. decl->name = name;
  1826. decl->script = file;
  1827. decl->validState = 0;
  1828. decl->node = NULL;
  1829. decl->objType = st;
  1830. namedTypeDeclarations.PushLast(decl);
  1831. }
  1832. node->Destroy(engine);
  1833. if( r < 0 )
  1834. {
  1835. engine->ConfigError(r);
  1836. }
  1837. return 0;
  1838. }
  1839. void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray<asCDataType> &parameterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate)
  1840. {
  1841. node = node->firstChild;
  1842. // Is the function a private class method?
  1843. isPrivate = false;
  1844. if( node->tokenType == ttPrivate )
  1845. {
  1846. isPrivate = true;
  1847. node = node->next;
  1848. }
  1849. // Find the name
  1850. isConstructor = false;
  1851. isDestructor = false;
  1852. asCScriptNode *n = 0;
  1853. if( node->nodeType == snDataType )
  1854. n = node->next->next;
  1855. else
  1856. {
  1857. // If the first node is a ~ token, then we know it is a destructor
  1858. if( node->tokenType == ttBitNot )
  1859. {
  1860. n = node->next;
  1861. isDestructor = true;
  1862. }
  1863. else
  1864. {
  1865. n = node;
  1866. isConstructor = true;
  1867. }
  1868. }
  1869. name.Assign(&file->code[n->tokenPos], n->tokenLength);
  1870. // Initialize a script function object for registration
  1871. if( !isConstructor && !isDestructor )
  1872. {
  1873. returnType = CreateDataTypeFromNode(node, file);
  1874. returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0);
  1875. }
  1876. else
  1877. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  1878. // Is this a const method?
  1879. if( objType && n->next->next && n->next->next->tokenType == ttConst )
  1880. isConstMethod = true;
  1881. else
  1882. isConstMethod = false;
  1883. // Count the number of parameters
  1884. int count = 0;
  1885. asCScriptNode *c = n->next->firstChild;
  1886. while( c )
  1887. {
  1888. count++;
  1889. c = c->next->next;
  1890. if( c && c->nodeType == snIdentifier )
  1891. c = c->next;
  1892. if( c && c->nodeType == snExpression )
  1893. c = c->next;
  1894. }
  1895. // Get the parameter types
  1896. parameterTypes.Allocate(count, false);
  1897. inOutFlags.Allocate(count, false);
  1898. defaultArgs.Allocate(count, false);
  1899. n = n->next->firstChild;
  1900. while( n )
  1901. {
  1902. asETypeModifiers inOutFlag;
  1903. asCDataType type = CreateDataTypeFromNode(n, file);
  1904. type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
  1905. // Store the parameter type
  1906. parameterTypes.PushLast(type);
  1907. inOutFlags.PushLast(inOutFlag);
  1908. // Move to next parameter
  1909. n = n->next->next;
  1910. if( n && n->nodeType == snIdentifier )
  1911. n = n->next;
  1912. if( n && n->nodeType == snExpression )
  1913. {
  1914. // Strip out white space and comments to better share the string
  1915. asCString *defaultArgStr = asNEW(asCString);
  1916. *defaultArgStr = GetCleanExpressionString(n, file);
  1917. defaultArgs.PushLast(defaultArgStr);
  1918. n = n->next;
  1919. }
  1920. else
  1921. defaultArgs.PushLast(0);
  1922. }
  1923. }
  1924. asCString asCBuilder::GetCleanExpressionString(asCScriptNode *node, asCScriptCode *file)
  1925. {
  1926. asASSERT(node && node->nodeType == snExpression);
  1927. asCString str;
  1928. str.Assign(file->code + node->tokenPos, node->tokenLength);
  1929. asCString cleanStr;
  1930. for( asUINT n = 0; n < str.GetLength(); )
  1931. {
  1932. int len;
  1933. asETokenClass tok = engine->ParseToken(str.AddressOf() + n, str.GetLength() - n, &len);
  1934. if( tok != asTC_COMMENT && tok != asTC_WHITESPACE )
  1935. {
  1936. if( cleanStr.GetLength() ) cleanStr += " ";
  1937. cleanStr.Concatenate(str.AddressOf() + n, len);
  1938. }
  1939. n += len;
  1940. }
  1941. return cleanStr;
  1942. }
  1943. int asCBuilder::RegisterScriptFunction(int funcId, asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction)
  1944. {
  1945. asCString name;
  1946. asCDataType returnType;
  1947. asCArray<asCDataType> parameterTypes;
  1948. asCArray<asETypeModifiers> inOutFlags;
  1949. asCArray<asCString *> defaultArgs;
  1950. bool isConstMethod;
  1951. bool isConstructor;
  1952. bool isDestructor;
  1953. bool isPrivate;
  1954. GetParsedFunctionDetails(node, file, objType, name, returnType, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate);
  1955. // Check for name conflicts
  1956. if( !isConstructor && !isDestructor )
  1957. {
  1958. if( objType )
  1959. {
  1960. CheckNameConflictMember(objType, name.AddressOf(), node, file, false);
  1961. if( name == objType->name )
  1962. {
  1963. int r, c;
  1964. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1965. WriteError(file->name.AddressOf(), TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, r, c);
  1966. }
  1967. }
  1968. else
  1969. CheckNameConflict(name.AddressOf(), node, file);
  1970. }
  1971. else
  1972. {
  1973. // Verify that the name of the constructor/destructor is the same as the class
  1974. if( name != objType->name )
  1975. {
  1976. int r, c;
  1977. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1978. WriteError(file->name.AddressOf(), TXT_CONSTRUCTOR_NAME_ERROR, r, c);
  1979. }
  1980. if( isDestructor )
  1981. name = "~" + name;
  1982. }
  1983. if( !isInterface )
  1984. {
  1985. sFunctionDescription *func = asNEW(sFunctionDescription);
  1986. functions.PushLast(func);
  1987. func->script = file;
  1988. func->node = node;
  1989. func->name = name;
  1990. func->objType = objType;
  1991. func->funcId = funcId;
  1992. }
  1993. // Destructors may not have any parameters
  1994. if( isDestructor && parameterTypes.GetLength() > 0 )
  1995. {
  1996. int r, c;
  1997. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1998. WriteError(file->name.AddressOf(), TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, r, c);
  1999. }
  2000. // TODO: Much of this can probably be reduced by using the IsSignatureEqual method
  2001. // Check that the same function hasn't been registered already
  2002. asCArray<int> funcs;
  2003. GetFunctionDescriptions(name.AddressOf(), funcs);
  2004. if( funcs.GetLength() )
  2005. {
  2006. for( asUINT n = 0; n < funcs.GetLength(); ++n )
  2007. {
  2008. asCScriptFunction *func = GetFunctionDescription(funcs[n]);
  2009. if( parameterTypes.GetLength() == func->parameterTypes.GetLength() )
  2010. {
  2011. bool match = true;
  2012. if( func->objectType != objType )
  2013. {
  2014. match = false;
  2015. break;
  2016. }
  2017. for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
  2018. {
  2019. if( parameterTypes[p] != func->parameterTypes[p] )
  2020. {
  2021. match = false;
  2022. break;
  2023. }
  2024. }
  2025. if( match )
  2026. {
  2027. int r, c;
  2028. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2029. WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
  2030. break;
  2031. }
  2032. }
  2033. }
  2034. }
  2035. // Register the function
  2036. module->AddScriptFunction(file->idx, funcId, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), isInterface, objType, isConstMethod, isGlobalFunction, isPrivate);
  2037. // Make sure the default args are declared correctly
  2038. ValidateDefaultArgs(file, node, engine->scriptFunctions[funcId]);
  2039. if( objType )
  2040. {
  2041. engine->scriptFunctions[funcId]->AddRef();
  2042. if( isConstructor )
  2043. {
  2044. int factoryId = engine->GetNextScriptFunctionId();
  2045. if( parameterTypes.GetLength() == 0 )
  2046. {
  2047. // Overload the default constructor
  2048. engine->scriptFunctions[objType->beh.construct]->Release();
  2049. objType->beh.construct = funcId;
  2050. objType->beh.constructors[0] = funcId;
  2051. // Register the default factory as well
  2052. engine->scriptFunctions[objType->beh.factory]->Release();
  2053. objType->beh.factory = factoryId;
  2054. objType->beh.factories[0] = factoryId;
  2055. }
  2056. else
  2057. {
  2058. objType->beh.constructors.PushLast(funcId);
  2059. // Register the factory as well
  2060. objType->beh.factories.PushLast(factoryId);
  2061. }
  2062. // We must copy the default arg strings to avoid deleting the same object multiple times
  2063. for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
  2064. if( defaultArgs[n] )
  2065. defaultArgs[n] = asNEW(asCString)(*defaultArgs[n]);
  2066. asCDataType dt = asCDataType::CreateObjectHandle(objType, false);
  2067. module->AddScriptFunction(file->idx, factoryId, name.AddressOf(), dt, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
  2068. // Add a dummy function to the module so that it doesn't mix up the fund Ids
  2069. functions.PushLast(0);
  2070. // Compile the factory immediately
  2071. asCCompiler compiler(engine);
  2072. compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]);
  2073. engine->scriptFunctions[factoryId]->AddRef();
  2074. }
  2075. else if( isDestructor )
  2076. objType->beh.destruct = funcId;
  2077. else
  2078. objType->methods.PushLast(funcId);
  2079. }
  2080. // We need to delete the node already if this is an interface method
  2081. if( isInterface && node )
  2082. {
  2083. node->Destroy(engine);
  2084. }
  2085. return 0;
  2086. }
  2087. int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCScriptCode *file)
  2088. {
  2089. // Find name
  2090. asCScriptNode *f = node->firstChild;
  2091. asCScriptNode *n = f->firstChild->next->next;
  2092. // Check for name conflicts
  2093. asCString name(&file->code[n->tokenPos], n->tokenLength);
  2094. CheckNameConflict(name.AddressOf(), n, file);
  2095. // Initialize a script function object for registration
  2096. asCDataType returnType;
  2097. returnType = CreateDataTypeFromNode(f->firstChild, file);
  2098. returnType = ModifyDataTypeFromNode(returnType, f->firstChild->next, file, 0, 0);
  2099. // Count the parameters
  2100. int count = 0;
  2101. asCScriptNode *c = n->next->firstChild;
  2102. while( c )
  2103. {
  2104. count++;
  2105. c = c->next->next;
  2106. if( c && c->nodeType == snIdentifier )
  2107. c = c->next;
  2108. }
  2109. asCArray<asCDataType> parameterTypes(count);
  2110. asCArray<asETypeModifiers> inOutFlags(count);
  2111. n = n->next->firstChild;
  2112. while( n )
  2113. {
  2114. asETypeModifiers inOutFlag;
  2115. asCDataType type = CreateDataTypeFromNode(n, file);
  2116. type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
  2117. // Store the parameter type
  2118. parameterTypes.PushLast(type);
  2119. inOutFlags.PushLast(inOutFlag);
  2120. if( type.GetTokenType() == ttVoid )
  2121. {
  2122. int r, c;
  2123. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2124. asCString str;
  2125. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  2126. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  2127. break;
  2128. }
  2129. // Move to next parameter
  2130. n = n->next->next;
  2131. if( n && n->nodeType == snIdentifier )
  2132. n = n->next;
  2133. }
  2134. // Check that the same function hasn't been registered already
  2135. asCArray<int> funcs;
  2136. GetFunctionDescriptions(name.AddressOf(), funcs);
  2137. if( funcs.GetLength() )
  2138. {
  2139. for( asUINT n = 0; n < funcs.GetLength(); ++n )
  2140. {
  2141. asCScriptFunction *func = GetFunctionDescription(funcs[n]);
  2142. if( parameterTypes.GetLength() == func->parameterTypes.GetLength() )
  2143. {
  2144. bool match = true;
  2145. for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
  2146. {
  2147. if( parameterTypes[p] != func->parameterTypes[p] )
  2148. {
  2149. match = false;
  2150. break;
  2151. }
  2152. }
  2153. if( match )
  2154. {
  2155. int r, c;
  2156. file->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2157. WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
  2158. break;
  2159. }
  2160. }
  2161. }
  2162. }
  2163. // Read the module name as well
  2164. n = node->firstChild->next;
  2165. asCString moduleName;
  2166. moduleName.Assign(&file->code[n->tokenPos+1], n->tokenLength-2);
  2167. node->Destroy(engine);
  2168. // Register the function
  2169. module->AddImportedFunction(importID, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), moduleName);
  2170. return 0;
  2171. }
  2172. asCScriptFunction *asCBuilder::GetFunctionDescription(int id)
  2173. {
  2174. // TODO: import: This should be improved when the imported functions are removed
  2175. // Get the description from the engine
  2176. if( (id & 0xFFFF0000) == 0 )
  2177. return engine->scriptFunctions[id];
  2178. else
  2179. return engine->importedFunctions[id & 0xFFFF]->importedFunctionSignature;
  2180. }
  2181. void asCBuilder::GetFunctionDescriptions(const char *name, asCArray<int> &funcs)
  2182. {
  2183. asUINT n;
  2184. // TODO: optimize: Improve linear search
  2185. for( n = 0; n < module->scriptFunctions.GetLength(); n++ )
  2186. {
  2187. if( module->scriptFunctions[n]->name == name &&
  2188. module->scriptFunctions[n]->objectType == 0 )
  2189. funcs.PushLast(module->scriptFunctions[n]->id);
  2190. }
  2191. // TODO: optimize: Improve linear search
  2192. for( n = 0; n < module->bindInformations.GetLength(); n++ )
  2193. {
  2194. if( module->bindInformations[n]->importedFunctionSignature->name == name )
  2195. funcs.PushLast(module->bindInformations[n]->importedFunctionSignature->id);
  2196. }
  2197. // TODO: optimize: Improve linear search
  2198. // TODO: optimize: Use the registeredGlobalFunctions array instead
  2199. for( n = 0; n < engine->scriptFunctions.GetLength(); n++ )
  2200. {
  2201. if( engine->scriptFunctions[n] &&
  2202. engine->scriptFunctions[n]->funcType == asFUNC_SYSTEM &&
  2203. engine->scriptFunctions[n]->objectType == 0 &&
  2204. engine->scriptFunctions[n]->name == name )
  2205. {
  2206. // Find the config group for the global function
  2207. asCConfigGroup *group = engine->FindConfigGroupForFunction(engine->scriptFunctions[n]->id);
  2208. if( !group || group->HasModuleAccess(module->name.AddressOf()) )
  2209. funcs.PushLast(engine->scriptFunctions[n]->id);
  2210. }
  2211. }
  2212. }
  2213. void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope)
  2214. {
  2215. if( scope != "" )
  2216. {
  2217. // Find the base class with the specified scope
  2218. while( objectType && objectType->name != scope )
  2219. objectType = objectType->derivedFrom;
  2220. // If the scope is not any of the base classes, then return no methods
  2221. if( objectType == 0 )
  2222. return;
  2223. }
  2224. // TODO: optimize: Improve linear search
  2225. if( objIsConst )
  2226. {
  2227. // Only add const methods to the list
  2228. for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
  2229. {
  2230. if( engine->scriptFunctions[objectType->methods[n]]->name == name &&
  2231. engine->scriptFunctions[objectType->methods[n]]->isReadOnly )
  2232. {
  2233. // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
  2234. if( scope == "" )
  2235. methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
  2236. else
  2237. {
  2238. asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
  2239. asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
  2240. methods.PushLast(realFunc->id);
  2241. }
  2242. }
  2243. }
  2244. }
  2245. else
  2246. {
  2247. // TODO: Prefer non-const over const
  2248. for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
  2249. {
  2250. if( engine->scriptFunctions[objectType->methods[n]]->name == name )
  2251. {
  2252. // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
  2253. if( scope == "" )
  2254. methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
  2255. else
  2256. {
  2257. asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
  2258. asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
  2259. methods.PushLast(realFunc->id);
  2260. }
  2261. }
  2262. }
  2263. }
  2264. }
  2265. void asCBuilder::WriteInfo(const char *scriptname, const char *message, int r, int c, bool pre)
  2266. {
  2267. // Need to store the pre message in a structure
  2268. if( pre )
  2269. {
  2270. preMessage.isSet = true;
  2271. preMessage.c = c;
  2272. preMessage.r = r;
  2273. preMessage.message = message;
  2274. }
  2275. else
  2276. {
  2277. preMessage.isSet = false;
  2278. engine->WriteMessage(scriptname, r, c, asMSGTYPE_INFORMATION, message);
  2279. }
  2280. }
  2281. void asCBuilder::WriteError(const char *scriptname, const char *message, int r, int c)
  2282. {
  2283. numErrors++;
  2284. // Need to pass the preMessage first
  2285. if( preMessage.isSet )
  2286. WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
  2287. engine->WriteMessage(scriptname, r, c, asMSGTYPE_ERROR, message);
  2288. }
  2289. void asCBuilder::WriteWarning(const char *scriptname, const char *message, int r, int c)
  2290. {
  2291. numWarnings++;
  2292. // Need to pass the preMessage first
  2293. if( preMessage.isSet )
  2294. WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
  2295. engine->WriteMessage(scriptname, r, c, asMSGTYPE_WARNING, message);
  2296. }
  2297. asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, bool acceptHandleForScope, asCObjectType *templateType)
  2298. {
  2299. asASSERT(node->nodeType == snDataType);
  2300. asCDataType dt;
  2301. asCScriptNode *n = node->firstChild;
  2302. bool isConst = false;
  2303. bool isImplicitHandle = false;
  2304. if( n->tokenType == ttConst )
  2305. {
  2306. isConst = true;
  2307. n = n->next;
  2308. }
  2309. if( n->tokenType == ttIdentifier )
  2310. {
  2311. asCString str;
  2312. str.Assign(&file->code[n->tokenPos], n->tokenLength);
  2313. asCObjectType *ot = 0;
  2314. // If this is for a template type, then we must first determine if the
  2315. // identifier matches any of the template subtypes
  2316. // TODO: template: it should be possible to have more than one subtypes
  2317. if( templateType && (templateType->flags & asOBJ_TEMPLATE) && str == templateType->templateSubType.GetObjectType()->name )
  2318. ot = templateType->templateSubType.GetObjectType();
  2319. if( ot == 0 )
  2320. ot = GetObjectType(str.AddressOf());
  2321. if( ot )
  2322. {
  2323. if( ot->flags & asOBJ_IMPLICIT_HANDLE )
  2324. isImplicitHandle = true;
  2325. // Find the config group for the object type
  2326. asCConfigGroup *group = engine->FindConfigGroupForObjectType(ot);
  2327. if( !module || !group || group->HasModuleAccess(module->name.AddressOf()) )
  2328. {
  2329. if(asOBJ_TYPEDEF == (ot->flags & asOBJ_TYPEDEF))
  2330. {
  2331. // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two)
  2332. // Create primitive data type based on object flags
  2333. dt = ot->templateSubType;
  2334. dt.MakeReadOnly(isConst);
  2335. }
  2336. else
  2337. {
  2338. if( ot->flags & asOBJ_TEMPLATE )
  2339. {
  2340. n = n->next;
  2341. // Check if the subtype is a type or the template's subtype
  2342. // if it is the template's subtype then this is the actual template type,
  2343. // orderwise it is a template instance.
  2344. // Only do this for application registered interface, as the
  2345. // scripts cannot implement templates.
  2346. asCDataType subType = CreateDataTypeFromNode(n, file, false, module ? 0 : ot);
  2347. if( subType.GetObjectType() != ot->templateSubType.GetObjectType() )
  2348. {
  2349. // This is a template instance
  2350. // Need to find the correct object type
  2351. asCObjectType *otInstance = engine->GetTemplateInstanceType(ot, subType);
  2352. if( !otInstance )
  2353. {
  2354. asCString msg;
  2355. msg.Format(TXT_CANNOT_INSTANCIATE_TEMPLATE_s_WITH_s, ot->name.AddressOf(), subType.Format().AddressOf());
  2356. int r, c;
  2357. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2358. WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
  2359. }
  2360. ot = otInstance;
  2361. }
  2362. }
  2363. // Create object data type
  2364. if( ot )
  2365. dt = asCDataType::CreateObject(ot, isConst);
  2366. else
  2367. dt = asCDataType::CreatePrimitive(ttInt, isConst);
  2368. }
  2369. }
  2370. else
  2371. {
  2372. asCString msg;
  2373. msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf());
  2374. int r, c;
  2375. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2376. WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
  2377. dt.SetTokenType(ttInt);
  2378. }
  2379. }
  2380. else if( ot == 0 )
  2381. {
  2382. // It can still be a function definition
  2383. asCScriptFunction *funcdef = GetFuncDef(str.AddressOf());
  2384. if( funcdef )
  2385. {
  2386. dt = asCDataType::CreateFuncDef(funcdef);
  2387. }
  2388. else if( funcdef == 0 )
  2389. {
  2390. asCString msg;
  2391. msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, (const char *)str.AddressOf());
  2392. int r, c;
  2393. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2394. WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
  2395. dt = asCDataType::CreatePrimitive(ttInt, isConst);
  2396. return dt;
  2397. }
  2398. }
  2399. }
  2400. else
  2401. {
  2402. // Create primitive data type
  2403. dt = asCDataType::CreatePrimitive(n->tokenType, isConst);
  2404. }
  2405. // Determine array dimensions and object handles
  2406. n = n->next;
  2407. while( n && (n->tokenType == ttOpenBracket || n->tokenType == ttHandle) )
  2408. {
  2409. if( n->tokenType == ttOpenBracket )
  2410. {
  2411. // Make sure the sub type can be instanciated
  2412. if( !dt.CanBeInstanciated() )
  2413. {
  2414. int r, c;
  2415. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2416. asCString str;
  2417. // TODO: Change to "Array sub type cannot be 'type'"
  2418. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
  2419. WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
  2420. }
  2421. // Make the type an array (or multidimensional array)
  2422. if( dt.MakeArray(engine) < 0 )
  2423. {
  2424. int r, c;
  2425. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2426. WriteError(file->name.AddressOf(), TXT_NO_DEFAULT_ARRAY_TYPE, r, c);
  2427. break;
  2428. }
  2429. }
  2430. else
  2431. {
  2432. // Make the type a handle
  2433. if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
  2434. {
  2435. int r, c;
  2436. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2437. WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
  2438. break;
  2439. }
  2440. }
  2441. n = n->next;
  2442. }
  2443. if( isImplicitHandle )
  2444. {
  2445. // Make the type a handle
  2446. if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
  2447. {
  2448. int r, c;
  2449. file->ConvertPosToRowCol(n->tokenPos, &r, &c);
  2450. WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
  2451. }
  2452. }
  2453. return dt;
  2454. }
  2455. asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle)
  2456. {
  2457. asCDataType dt = type;
  2458. if( inOutFlags ) *inOutFlags = asTM_NONE;
  2459. // Is the argument sent by reference?
  2460. asCScriptNode *n = node->firstChild;
  2461. if( n && n->tokenType == ttAmp )
  2462. {
  2463. dt.MakeReference(true);
  2464. n = n->next;
  2465. if( n )
  2466. {
  2467. if( inOutFlags )
  2468. {
  2469. if( n->tokenType == ttIn )
  2470. *inOutFlags = asTM_INREF;
  2471. else if( n->tokenType == ttOut )
  2472. *inOutFlags = asTM_OUTREF;
  2473. else if( n->tokenType == ttInOut )
  2474. *inOutFlags = asTM_INOUTREF;
  2475. else
  2476. asASSERT(false);
  2477. }
  2478. n = n->next;
  2479. }
  2480. else
  2481. {
  2482. if( inOutFlags )
  2483. *inOutFlags = asTM_INOUTREF; // ttInOut
  2484. }
  2485. if( !engine->ep.allowUnsafeReferences &&
  2486. inOutFlags && *inOutFlags == asTM_INOUTREF )
  2487. {
  2488. // Verify that the base type support &inout parameter types
  2489. if( !dt.IsObject() || dt.IsObjectHandle() || !dt.GetObjectType()->beh.addref || !dt.GetObjectType()->beh.release )
  2490. {
  2491. int r, c;
  2492. file->ConvertPosToRowCol(node->firstChild->tokenPos, &r, &c);
  2493. WriteError(file->name.AddressOf(), TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, r, c);
  2494. }
  2495. }
  2496. }
  2497. if( autoHandle ) *autoHandle = false;
  2498. if( n && n->tokenType == ttPlus )
  2499. {
  2500. if( autoHandle ) *autoHandle = true;
  2501. }
  2502. return dt;
  2503. }
  2504. asCObjectType *asCBuilder::GetObjectType(const char *type)
  2505. {
  2506. // TODO: Only search in config groups to which the module has access
  2507. asCObjectType *ot = engine->GetObjectType(type);
  2508. if( !ot && module )
  2509. ot = module->GetObjectType(type);
  2510. return ot;
  2511. }
  2512. asCScriptFunction *asCBuilder::GetFuncDef(const char *type)
  2513. {
  2514. for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ )
  2515. {
  2516. // TODO: Only return the definitions for the config groups that the module has access to
  2517. if( engine->registeredFuncDefs[n]->name == type )
  2518. {
  2519. return engine->registeredFuncDefs[n];
  2520. }
  2521. }
  2522. if( module )
  2523. {
  2524. for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ )
  2525. {
  2526. if( module->funcDefs[n]->name == type )
  2527. {
  2528. return module->funcDefs[n];
  2529. }
  2530. }
  2531. }
  2532. return 0;
  2533. }
  2534. int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue)
  2535. {
  2536. if( !objType || !(objType->flags & asOBJ_ENUM) )
  2537. return 0;
  2538. for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n )
  2539. {
  2540. if( objType->enumValues[n]->name == name )
  2541. {
  2542. outDt = asCDataType::CreateObject(objType, true);
  2543. outValue = objType->enumValues[n]->value;
  2544. return 1;
  2545. }
  2546. }
  2547. return 0;
  2548. }
  2549. int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue)
  2550. {
  2551. bool found = false;
  2552. // Search all available enum types
  2553. asUINT t;
  2554. for( t = 0; t < engine->objectTypes.GetLength(); t++ )
  2555. {
  2556. asCObjectType *ot = engine->objectTypes[t];
  2557. if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
  2558. {
  2559. if( !found )
  2560. {
  2561. found = true;
  2562. }
  2563. else
  2564. {
  2565. // Found more than one value in different enum types
  2566. return 2;
  2567. }
  2568. }
  2569. }
  2570. for( t = 0; t < module->enumTypes.GetLength(); t++ )
  2571. {
  2572. asCObjectType *ot = module->enumTypes[t];
  2573. if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
  2574. {
  2575. if( !found )
  2576. {
  2577. found = true;
  2578. }
  2579. else
  2580. {
  2581. // Found more than one value in different enum types
  2582. return 2;
  2583. }
  2584. }
  2585. }
  2586. if( found )
  2587. return 1;
  2588. // Didn't find any value
  2589. return 0;
  2590. }
  2591. END_AS_NAMESPACE