| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2011 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- The original version of this library can be located at:
- http://www.angelcode.com/angelscript/
- Andreas Jonsson
- [email protected]
- */
- // Modified by Lasse Öörni for Urho3D
- //
- // as_builder.cpp
- //
- // This is the class that manages the compilation of the scripts
- //
- #include "as_config.h"
- #include "as_builder.h"
- #include "as_parser.h"
- #include "as_compiler.h"
- #include "as_tokendef.h"
- #include "as_string_util.h"
- #include "as_outputbuffer.h"
- #include "as_texts.h"
- #include "as_scriptobject.h"
- BEGIN_AS_NAMESPACE
- asCBuilder::asCBuilder(asCScriptEngine *engine, asCModule *module)
- {
- this->engine = engine;
- this->module = module;
- }
- asCBuilder::~asCBuilder()
- {
- asUINT n;
- // Free all functions
- for( n = 0; n < functions.GetLength(); n++ )
- {
- if( functions[n] )
- {
- if( functions[n]->node )
- {
- functions[n]->node->Destroy(engine);
- }
- asDELETE(functions[n],sFunctionDescription);
- }
- functions[n] = 0;
- }
- // Free all global variables
- for( n = 0; n < globVariables.GetLength(); n++ )
- {
- if( globVariables[n] )
- {
- if( globVariables[n]->nextNode )
- {
- globVariables[n]->nextNode->Destroy(engine);
- }
- asDELETE(globVariables[n],sGlobalVariableDescription);
- globVariables[n] = 0;
- }
- }
- // Free all the loaded files
- for( n = 0; n < scripts.GetLength(); n++ )
- {
- if( scripts[n] )
- {
- asDELETE(scripts[n],asCScriptCode);
- }
- scripts[n] = 0;
- }
- // Free all class declarations
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- if( classDeclarations[n] )
- {
- if( classDeclarations[n]->node )
- {
- classDeclarations[n]->node->Destroy(engine);
- }
- asDELETE(classDeclarations[n],sClassDeclaration);
- classDeclarations[n] = 0;
- }
- }
- for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
- {
- if( interfaceDeclarations[n] )
- {
- if( interfaceDeclarations[n]->node )
- {
- interfaceDeclarations[n]->node->Destroy(engine);
- }
- asDELETE(interfaceDeclarations[n],sClassDeclaration);
- interfaceDeclarations[n] = 0;
- }
- }
- for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
- {
- if( namedTypeDeclarations[n] )
- {
- if( namedTypeDeclarations[n]->node )
- {
- namedTypeDeclarations[n]->node->Destroy(engine);
- }
- asDELETE(namedTypeDeclarations[n],sClassDeclaration);
- namedTypeDeclarations[n] = 0;
- }
- }
- for( n = 0; n < funcDefs.GetLength(); n++ )
- {
- if( funcDefs[n] )
- {
- if( funcDefs[n]->node )
- funcDefs[n]->node->Destroy(engine);
- asDELETE(funcDefs[n],sFuncDef);
- funcDefs[n] = 0;
- }
- }
- }
- int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy)
- {
- asCScriptCode *script = asNEW(asCScriptCode);
- int r = script->SetCode(name, code, codeLength, makeCopy);
- script->lineOffset = lineOffset;
- script->idx = sectionIdx;
- scripts.PushLast(script);
- return r;
- }
- int asCBuilder::Build()
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- ParseScripts();
- CompileClasses();
- CompileGlobalVariables();
- CompileFunctions();
- if( numErrors > 0 )
- return asERROR;
- return asSUCCESS;
- }
- int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset)
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- // Add the string to the script code
- asCScriptCode *script = asNEW(asCScriptCode);
- script->SetCode(sectionName, code, true);
- script->lineOffset = lineOffset;
- scripts.PushLast(script);
- // Parse the string
- asCParser parser(this);
- if( parser.ParseScript(scripts[0]) < 0 )
- return asERROR;
- asCScriptNode *node = parser.GetScriptNode();
- // Make sure there is nothing else than the global variable in the script code
- if( node == 0 ||
- node->firstChild == 0 ||
- node->firstChild != node->lastChild ||
- node->firstChild->nodeType != snGlobalVar )
- {
- WriteError(script->name.AddressOf(), TXT_ONLY_ONE_VARIABLE_ALLOWED, 0, 0);
- return asERROR;
- }
- node = node->firstChild;
- node->DisconnectParent();
- RegisterGlobalVar(node, script);
- CompileGlobalVariables();
- if( numErrors > 0 )
- {
- // Remove the variable from the module, if it was registered
- if( globVariables.GetLength() > 0 )
- {
- module->RemoveGlobalVar(module->GetGlobalVarCount()-1);
- }
- return asERROR;
- }
- return 0;
- }
- int asCBuilder::ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func)
- {
- int firstArgWithDefaultValue = -1;
- for( asUINT n = 0; n < func->defaultArgs.GetLength(); n++ )
- {
- if( func->defaultArgs[n] )
- firstArgWithDefaultValue = n;
- else if( firstArgWithDefaultValue >= 0 )
- {
- int r, c;
- script->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_DEF_ARG_MISSING_IN_FUNC_s, func->GetDeclaration());
- WriteError(script->name.AddressOf(), str.AddressOf(), r, c);
- return asINVALID_DECLARATION;
- }
- }
- return 0;
- }
- int asCBuilder::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc)
- {
- asASSERT(outFunc != 0);
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- // Add the string to the script code
- asCScriptCode *script = asNEW(asCScriptCode);
- script->SetCode(sectionName, code, true);
- script->lineOffset = lineOffset;
- scripts.PushLast(script);
- // Parse the string
- asCParser parser(this);
- if( parser.ParseScript(scripts[0]) < 0 )
- return asERROR;
- asCScriptNode *node = parser.GetScriptNode();
- // Make sure there is nothing else than the function in the script code
- if( node == 0 ||
- node->firstChild == 0 ||
- node->firstChild != node->lastChild ||
- node->firstChild->nodeType != snFunction )
- {
- WriteError(script->name.AddressOf(), TXT_ONLY_ONE_FUNCTION_ALLOWED, 0, 0);
- return asERROR;
- }
- // Find the function node
- node = node->firstChild;
- // Create the function
- bool isConstructor, isDestructor, isPrivate;
- asCScriptFunction *func = asNEW(asCScriptFunction)(engine,module,asFUNC_SCRIPT);
- GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterTypes, func->inOutFlags, func->defaultArgs, func->isReadOnly, isConstructor, isDestructor, isPrivate);
- func->id = engine->GetNextScriptFunctionId();
- func->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : "");
- // Make sure the default args are declared correctly
- int r = ValidateDefaultArgs(script, node, func);
- if( r < 0 )
- {
- func->Release();
- return asERROR;
- }
- // Tell the engine that the function exists already so the compiler can access it
- if( compileFlags & asCOMP_ADD_TO_MODULE )
- {
- int r = CheckNameConflict(func->name.AddressOf(), node, scripts[0]);
- if( r < 0 )
- {
- func->Release();
- return asERROR;
- }
- module->globalFunctions.PushLast(func);
- func->AddRef();
- module->AddScriptFunction(func);
- }
- else
- engine->SetScriptFunction(func);
- // Fill in the function info for the builder too
- node->DisconnectParent();
- sFunctionDescription *funcDesc = asNEW(sFunctionDescription);
- functions.PushLast(funcDesc);
- funcDesc->script = scripts[0];
- funcDesc->node = node;
- funcDesc->name = func->name;
- funcDesc->funcId = func->id;
- asCCompiler compiler(engine);
- if( compiler.CompileFunction(this, functions[0]->script, functions[0]->node, func) >= 0 )
- {
- // Return the function
- *outFunc = func;
- }
- else
- {
- // If the function was added to the module then remove it again
- if( compileFlags & asCOMP_ADD_TO_MODULE )
- {
- module->globalFunctions.RemoveValue(func);
- module->scriptFunctions.RemoveValue(func);
- func->Release();
- func->Release();
- }
- func->Release();
- return asERROR;
- }
- return asSUCCESS;
- }
- void asCBuilder::ParseScripts()
- {
- asCArray<asCParser*> parsers((int)scripts.GetLength());
- // Parse all the files as if they were one
- asUINT n = 0;
- for( n = 0; n < scripts.GetLength(); n++ )
- {
- asCParser *parser = asNEW(asCParser)(this);
- parsers.PushLast(parser);
- // Parse the script file
- parser->ParseScript(scripts[n]);
- }
- if( numErrors == 0 )
- {
- // Find all type declarations
- for( n = 0; n < scripts.GetLength(); n++ )
- {
- asCScriptNode *node = parsers[n]->GetScriptNode();
- // Find structure definitions first
- node = node->firstChild;
- while( node )
- {
- asCScriptNode *next = node->next;
- if( node->nodeType == snClass )
- {
- node->DisconnectParent();
- RegisterClass(node, scripts[n]);
- }
- else if( node->nodeType == snInterface )
- {
- node->DisconnectParent();
- RegisterInterface(node, scripts[n]);
- }
- // Handle enumeration
- else if( node->nodeType == snEnum )
- {
- node->DisconnectParent();
- RegisterEnum(node, scripts[n]);
- }
- // Handle typedef
- else if( node->nodeType == snTypedef )
- {
- node->DisconnectParent();
- RegisterTypedef(node, scripts[n]);
- }
- else if( node->nodeType == snFuncDef )
- {
- node->DisconnectParent();
- RegisterFuncDef(node, scripts[n]);
- }
- node = next;
- }
- }
- // Register the complete function definitions
- for( n = 0; n < funcDefs.GetLength(); n++ )
- {
- CompleteFuncDef(funcDefs[n]);
- }
- // Register script methods found in the interfaces
- for( n = 0; n < interfaceDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = interfaceDeclarations[n];
- if( decl->isExistingShared ) continue; // TODO: shared: Should really verify that the methods match the original
- asCScriptNode *node = decl->node->firstChild->next;
- while( node )
- {
- asCScriptNode *next = node->next;
- if( node->nodeType == snFunction )
- {
- node->DisconnectParent();
- RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType, true);
- }
- node = next;
- }
- }
- // Now the interfaces have been completely established, now we need to determine if
- // the same interface has already been registered before, and if so reuse the interface id.
- module->ResolveInterfaceIds();
- // Register script methods found in the structures
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- if( decl->isExistingShared ) continue; // TODO: shared: Should really verify that the methods match the original
- asCScriptNode *node = decl->node->firstChild->next;
- // Skip list of classes and interfaces
- while( node && node->nodeType == snIdentifier )
- node = node->next;
- while( node )
- {
- asCScriptNode *next = node->next;
- if( node->nodeType == snFunction )
- {
- node->DisconnectParent();
- RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, decl->script, decl->objType);
- }
- node = next;
- }
- // Make sure the default factory & constructor exists for classes
- if( decl->objType->beh.construct == engine->scriptTypeBehaviours.beh.construct )
- {
- AddDefaultConstructor(decl->objType, decl->script);
- }
- }
- // Find other global nodes
- for( n = 0; n < scripts.GetLength(); n++ )
- {
- // Find other global nodes
- asCScriptNode *node = parsers[n]->GetScriptNode();
- node = node->firstChild;
- while( node )
- {
- asCScriptNode *next = node->next;
- node->DisconnectParent();
- if( node->nodeType == snFunction )
- {
- RegisterScriptFunction(engine->GetNextScriptFunctionId(), node, scripts[n], 0, false, true);
- }
- else if( node->nodeType == snGlobalVar )
- {
- RegisterGlobalVar(node, scripts[n]);
- }
- else if( node->nodeType == snImport )
- {
- RegisterImportedFunction(module->GetNextImportedFunctionId(), node, scripts[n]);
- }
- else
- {
- // Unused script node
- int r, c;
- scripts[n]->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteWarning(scripts[n]->name.AddressOf(), TXT_UNUSED_SCRIPT_NODE, r, c);
- node->Destroy(engine);
- }
- node = next;
- }
- }
- }
- for( n = 0; n < parsers.GetLength(); n++ )
- {
- asDELETE(parsers[n],asCParser);
- }
- }
- void asCBuilder::CompileFunctions()
- {
- // Compile each function
- for( asUINT n = 0; n < functions.GetLength(); n++ )
- {
- if( functions[n] == 0 ) continue;
- asCCompiler compiler(engine);
- asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId];
- if( functions[n]->node )
- {
- int r, c;
- functions[n]->script->ConvertPosToRowCol(functions[n]->node->tokenPos, &r, &c);
- asCString str = func->GetDeclarationStr();
- str.Format(TXT_COMPILING_s, str.AddressOf());
- WriteInfo(functions[n]->script->name.AddressOf(), str.AddressOf(), r, c, true);
- compiler.CompileFunction(this, functions[n]->script, functions[n]->node, func);
- preMessage.isSet = false;
- }
- else
- {
- // This is the default constructor, that is generated
- // automatically if not implemented by the user.
- asASSERT( functions[n]->name == functions[n]->objType->name );
- compiler.CompileDefaultConstructor(this, functions[n]->script, func);
- }
- }
- }
- int asCBuilder::ParseDataType(const char *datatype, asCDataType *result)
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- asCScriptCode source;
- source.SetCode("", datatype, true);
- asCParser parser(this);
- int r = parser.ParseDataType(&source);
- if( r < 0 )
- return asINVALID_TYPE;
- // Get data type and property name
- asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
- *result = CreateDataTypeFromNode(dataType, &source, true);
- if( numErrors > 0 )
- return asINVALID_TYPE;
- return asSUCCESS;
- }
- int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCString *subtypeName)
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- asCScriptCode source;
- source.SetCode("", decl, true);
- asCParser parser(this);
- int r = parser.ParseTemplateDecl(&source);
- if( r < 0 )
- return asINVALID_TYPE;
- // Get the template name and subtype name
- asCScriptNode *node = parser.GetScriptNode()->firstChild;
- name->Assign(&decl[node->tokenPos], node->tokenLength);
- node = node->next;
- subtypeName->Assign(&decl[node->tokenPos], node->tokenLength);
- // TODO: template: check for name conflicts
- if( numErrors > 0 )
- return asINVALID_DECLARATION;
- return asSUCCESS;
- }
- int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &name, asCDataType &type)
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- if( dt )
- {
- // Verify that the object type exist
- if( dt->GetObjectType() == 0 )
- return asINVALID_OBJECT;
- }
- // Check property declaration and type
- asCScriptCode source;
- source.SetCode(TXT_PROPERTY, decl, true);
- asCParser parser(this);
- int r = parser.ParsePropertyDeclaration(&source);
- if( r < 0 )
- return asINVALID_DECLARATION;
- // Get data type and property name
- asCScriptNode *dataType = parser.GetScriptNode()->firstChild;
- asCScriptNode *nameNode = dataType->next;
- type = CreateDataTypeFromNode(dataType, &source);
- name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength);
- // Validate that the type really can be a registered property
- // We cannot use CanBeInstanciated, as it is allowed to register
- // properties of type that cannot otherwise be instanciated
- if( type.GetFuncDef() && !type.IsObjectHandle() )
- {
- // Function definitions must always be handles
- return asINVALID_DECLARATION;
- }
- // Verify property name
- if( dt )
- {
- if( CheckNameConflictMember(dt->GetObjectType(), name.AddressOf(), nameNode, &source, true) < 0 )
- return asNAME_TAKEN;
- }
- else
- {
- if( CheckNameConflict(name.AddressOf(), nameNode, &source) < 0 )
- return asNAME_TAKEN;
- }
- if( numErrors > 0 )
- return asINVALID_DECLARATION;
- return asSUCCESS;
- }
- asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop)
- {
- asASSERT(obj.GetObjectType() != 0);
- // TODO: optimize: Improve linear search
- asCArray<asCObjectProperty *> &props = obj.GetObjectType()->properties;
- for( asUINT n = 0; n < props.GetLength(); n++ )
- {
- if( props[n]->name == prop )
- {
- if( module->accessMask & props[n]->accessMask )
- return props[n];
- else
- return 0;
- }
- }
- return 0;
- }
- asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp)
- {
- asUINT n;
- if( isCompiled ) *isCompiled = true;
- if( isPureConstant ) *isPureConstant = false;
- if( isAppProp ) *isAppProp = false;
- // TODO: optimize: Improve linear search
- // Check application registered properties
- asCArray<asCGlobalProperty *> *props = &(engine->registeredGlobalProps);
- for( n = 0; n < props->GetLength(); ++n )
- if( (*props)[n] && (*props)[n]->name == prop )
- {
- if( module )
- {
- // Determine if the module has access to the property
- if( module->accessMask & (*props)[n]->accessMask )
- {
- #ifdef AS_DEPRECATED
- // deprecated since 2011-10-04
- // Find the config group for the global property
- asCConfigGroup *group = engine->FindConfigGroupForGlobalVar((*props)[n]->id);
- if( !group || group->HasModuleAccess(module->name.AddressOf()) )
- continue;
- #endif
- if( isAppProp ) *isAppProp = true;
- return (*props)[n];
- }
- }
- else
- {
- // We're not compiling a module right now, so it must be a registered global property
- if( isAppProp ) *isAppProp = true;
- return (*props)[n];
- }
- }
- // TODO: optimize: Improve linear search
- // Check properties being compiled now
- asCArray<sGlobalVariableDescription *> *gvars = &globVariables;
- for( n = 0; n < gvars->GetLength(); ++n )
- {
- if( (*gvars)[n] && (*gvars)[n]->name == prop )
- {
- if( isCompiled ) *isCompiled = (*gvars)[n]->isCompiled;
- if( isPureConstant ) *isPureConstant = (*gvars)[n]->isPureConstant;
- if( constantValue ) *constantValue = (*gvars)[n]->constantValue;
- return (*gvars)[n]->property;
- }
- }
- // TODO: optimize: Improve linear search
- // Check previously compiled global variables
- if( module )
- {
- props = &module->scriptGlobals;
- for( n = 0; n < props->GetLength(); ++n )
- if( (*props)[n]->name == prop )
- return (*props)[n];
- }
- return 0;
- }
- int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray<bool> *paramAutoHandles, bool *returnAutoHandle)
- {
- // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function?
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- asCScriptCode source;
- source.SetCode(TXT_SYSTEM_FUNCTION, decl, true);
- asCParser parser(this);
- int r = parser.ParseFunctionDefinition(&source);
- if( r < 0 )
- return asINVALID_DECLARATION;
- asCScriptNode *node = parser.GetScriptNode();
- // Find name
- asCScriptNode *n = node->firstChild->next->next;
- func->name.Assign(&source.code[n->tokenPos], n->tokenLength);
- // Initialize a script function object for registration
- bool autoHandle;
- // Scoped reference types are allowed to use handle when returned from application functions
- func->returnType = CreateDataTypeFromNode(node->firstChild, &source, true, objType);
- func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle);
- if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) )
- return asINVALID_DECLARATION;
- if( returnAutoHandle ) *returnAutoHandle = autoHandle;
- // Reference types cannot be returned by value from system functions
- if( isSystemFunction &&
- (func->returnType.GetObjectType() &&
- (func->returnType.GetObjectType()->flags & asOBJ_REF)) &&
- !(func->returnType.IsReference() ||
- func->returnType.IsObjectHandle()) )
- return asINVALID_DECLARATION;
- // Count number of parameters
- int paramCount = 0;
- n = n->next->firstChild;
- while( n )
- {
- paramCount++;
- n = n->next->next;
- if( n && n->nodeType == snIdentifier )
- n = n->next;
- if( n && n->nodeType == snExpression )
- n = n->next;
- }
- // Preallocate memory
- func->parameterTypes.Allocate(paramCount, false);
- func->inOutFlags.Allocate(paramCount, false);
- func->defaultArgs.Allocate(paramCount, false);
- if( paramAutoHandles ) paramAutoHandles->Allocate(paramCount, false);
- n = node->firstChild->next->next->next->firstChild;
- while( n )
- {
- asETypeModifiers inOutFlags;
- asCDataType type = CreateDataTypeFromNode(n, &source, false, objType);
- type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle);
- // Reference types cannot be passed by value to system functions
- if( isSystemFunction &&
- (type.GetObjectType() &&
- (type.GetObjectType()->flags & asOBJ_REF)) &&
- !(type.IsReference() ||
- type.IsObjectHandle()) )
- return asINVALID_DECLARATION;
- // Store the parameter type
- func->parameterTypes.PushLast(type);
- func->inOutFlags.PushLast(inOutFlags);
- // Don't permit void parameters
- if( type.GetTokenType() == ttVoid )
- return asINVALID_DECLARATION;
- if( autoHandle && (!type.IsObjectHandle() || type.IsReference()) )
- return asINVALID_DECLARATION;
- if( paramAutoHandles ) paramAutoHandles->PushLast(autoHandle);
- // Make sure that var type parameters are references
- if( type.GetTokenType() == ttQuestion &&
- !type.IsReference() )
- return asINVALID_DECLARATION;
- // Move to next parameter
- n = n->next->next;
- if( n && n->nodeType == snIdentifier )
- n = n->next;
- if( n && n->nodeType == snExpression )
- {
- // Strip out white space and comments to better share the string
- asCString *defaultArgStr = asNEW(asCString);
- *defaultArgStr = GetCleanExpressionString(n, &source);
- func->defaultArgs.PushLast(defaultArgStr);
- n = n->next;
- }
- else
- func->defaultArgs.PushLast(0);
- }
- // Set the read-only flag if const is declared after parameter list
- if( node->lastChild->nodeType == snUndefined && node->lastChild->tokenType == ttConst )
- {
- if( objType == 0 )
- return asINVALID_DECLARATION;
- func->isReadOnly = true;
- }
- else
- func->isReadOnly = false;
- // Make sure the default args are declared correctly
- ValidateDefaultArgs(&source, node, func);
- if( numErrors > 0 || numWarnings > 0 )
- return asINVALID_DECLARATION;
- return 0;
- }
- int asCBuilder::ParseVariableDeclaration(const char *decl, asCObjectProperty *var)
- {
- numErrors = 0;
- numWarnings = 0;
- preMessage.isSet = false;
- asCScriptCode source;
- source.SetCode(TXT_VARIABLE_DECL, decl, true);
- asCParser parser(this);
- int r = parser.ParsePropertyDeclaration(&source);
- if( r < 0 )
- return asINVALID_DECLARATION;
- asCScriptNode *node = parser.GetScriptNode();
- // Find name
- asCScriptNode *n = node->firstChild->next;
- var->name.Assign(&source.code[n->tokenPos], n->tokenLength);
- // Initialize a script variable object for registration
- var->type = CreateDataTypeFromNode(node->firstChild, &source);
- if( numErrors > 0 || numWarnings > 0 )
- return asINVALID_DECLARATION;
- return 0;
- }
- int asCBuilder::CheckNameConflictMember(asCObjectType *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty)
- {
- // It's not necessary to check against object types
- // TODO: optimize: Improve linear search
- asCArray<asCObjectProperty *> &props = t->properties;
- for( asUINT n = 0; n < props.GetLength(); n++ )
- {
- if( props[n]->name == name )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- }
- // Property names must be checked against method names
- if( isProperty )
- {
- asCArray<int> methods = t->methods;
- for( asUINT n = 0; n < methods.GetLength(); n++ )
- {
- if( engine->scriptFunctions[methods[n]]->name == name )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_METHOD, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- }
- }
- return 0;
- }
- int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code)
- {
- // TODO: Must verify object types in all config groups, whether the module has access or not
- // Check against object types
- if( engine->GetObjectType(name) != 0 )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- // TODO: Must verify global properties in all config groups, whether the module has access or not
- // Check against global properties
- asCGlobalProperty *prop = GetGlobalProperty(name, 0, 0, 0, 0);
- if( prop )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- // TODO: Property names must be checked against function names
- // Check against class types
- asUINT n;
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- if( classDeclarations[n]->name == name )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_STRUCT, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- }
- // Check against named types
- for( n = 0; n < namedTypeDeclarations.GetLength(); n++ )
- {
- if( namedTypeDeclarations[n]->name == name )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- }
- // Must check for name conflicts with funcdefs
- for( n = 0; n < funcDefs.GetLength(); n++ )
- {
- if( funcDefs[n]->name == name )
- {
- if( code )
- {
- int r, c;
- code->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name);
- WriteError(code->name.AddressOf(), str.AddressOf(), r, c);
- }
- return -1;
- }
- }
- return 0;
- }
- int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file)
- {
- // Find the name
- asASSERT( node->firstChild->nodeType == snDataType );
- asCScriptNode *n = node->firstChild->next->next;
-
- asCString name;
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
- // Check for name conflict with other types
- int r = CheckNameConflict(name.AddressOf(), node, file);
- if( asSUCCESS != r )
- {
- node->Destroy(engine);
- return r;
- }
- // The function definition should be stored as a asCScriptFunction so that the application
- // can use the asIScriptFunction interface to enumerate the return type and parameters
- // The return type and parameter types aren't determined in this function. A second pass is
- // necessary after all type declarations have been identified.
- sFuncDef *fd = asNEW(sFuncDef);
- fd->name = name;
- fd->node = node;
- fd->script = file;
- fd->idx = module->AddFuncDef(name.AddressOf());
- funcDefs.PushLast(fd);
- return 0;
- }
- void asCBuilder::CompleteFuncDef(sFuncDef *funcDef)
- {
- asCDataType returnType;
- asCArray<asCDataType> parameterTypes;
- asCArray<asETypeModifiers> inOutFlags;
- asCArray<asCString *> defaultArgs;
- bool isConstMethod;
- bool isConstructor;
- bool isDestructor;
- bool isPrivate;
- GetParsedFunctionDetails(funcDef->node, funcDef->script, 0, funcDef->name, returnType, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate);
- asCScriptFunction *func = module->funcDefs[funcDef->idx];
- if( func )
- {
- func->returnType = returnType;
- for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
- {
- func->parameterTypes.PushLast(parameterTypes[p]);
- func->inOutFlags.PushLast(inOutFlags[p]);
- // Don't copy the default arg expression as it is not allowed for function definitions
- }
- }
- }
- int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file)
- {
- // Has the application disabled global vars?
- if( engine->ep.disallowGlobalVars )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_GLOBAL_VARS_NOT_ALLOWED, r, c);
- }
- // What data type is it?
- asCDataType type = CreateDataTypeFromNode(node->firstChild, file);
- if( !type.CanBeInstanciated() )
- {
- asCString str;
- // TODO: Change to "'type' cannot be declared as variable"
- str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- }
- asCScriptNode *n = node->firstChild->next;
- while( n )
- {
- // Verify that the name isn't taken
- asCString name(&file->code[n->tokenPos], n->tokenLength);
- CheckNameConflict(name.AddressOf(), n, file);
- // Register the global variable
- sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
- globVariables.PushLast(gvar);
- gvar->script = file;
- gvar->name = name;
- gvar->isCompiled = false;
- gvar->datatype = type;
- gvar->isEnumValue = false;
- // TODO: Give error message if wrong
- asASSERT(!gvar->datatype.IsReference());
- gvar->idNode = n;
- gvar->nextNode = 0;
- if( n->next &&
- (n->next->nodeType == snAssignment ||
- n->next->nodeType == snArgList ||
- n->next->nodeType == snInitList ) )
- {
- gvar->nextNode = n->next;
- n->next->DisconnectParent();
- }
- gvar->property = module->AllocateGlobalProperty(name.AddressOf(), gvar->datatype);
- gvar->index = gvar->property->id;
- n = n->next;
- }
- node->Destroy(engine);
- return 0;
- }
- int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file)
- {
- asCScriptNode *n = node->firstChild;
- asCString name(&file->code[n->tokenPos], n->tokenLength);
- bool isShared = false;
- if( name == SHARED_TOKEN )
- {
- isShared = true;
- n = n->next;
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
- }
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- CheckNameConflict(name.AddressOf(), n, file);
- sClassDeclaration *decl = asNEW(sClassDeclaration);
- classDeclarations.PushLast(decl);
- decl->name = name;
- decl->script = file;
- decl->node = node;
- // If this type is shared and there already exist another shared
- // type of the same name, then that one should be used instead of
- // creating a new one.
- if( isShared )
- {
- for( asUINT n = 0; n < engine->classTypes.GetLength(); n++ )
- {
- asCObjectType *st = engine->classTypes[n];
- if( st &&
- st->IsShared() &&
- st->name == name &&
- !st->IsInterface() )
- {
- // We'll use the existing type
- decl->isExistingShared = true;
- decl->objType = st;
- module->classTypes.PushLast(st);
- st->AddRef();
- return 0;
- }
- }
- }
- // Create a new object type for this class
- asCObjectType *st = asNEW(asCObjectType)(engine);
- st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
- if( isShared )
- st->flags |= asOBJ_SHARED;
- if( node->tokenType == ttHandle )
- st->flags |= asOBJ_IMPLICIT_HANDLE;
- st->size = sizeof(asCScriptObject);
- st->name = name;
- module->classTypes.PushLast(st);
- engine->classTypes.PushLast(st);
- st->AddRef();
- decl->objType = st;
- // Add script classes to the GC
- // TODO: optimize: Only add the class to the GC when the module won't use the type anymore
- engine->gc.AddScriptObjectToGC(st, &engine->objectTypeBehaviours);
- // Use the default script class behaviours
- st->beh = engine->scriptTypeBehaviours.beh;
- // TODO: Move this to asCObjectType so that the asCRestore can reuse it
- engine->scriptFunctions[st->beh.addref]->AddRef();
- engine->scriptFunctions[st->beh.release]->AddRef();
- engine->scriptFunctions[st->beh.gcEnumReferences]->AddRef();
- engine->scriptFunctions[st->beh.gcGetFlag]->AddRef();
- engine->scriptFunctions[st->beh.gcGetRefCount]->AddRef();
- engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRef();
- engine->scriptFunctions[st->beh.gcSetFlag]->AddRef();
- engine->scriptFunctions[st->beh.copy]->AddRef();
- engine->scriptFunctions[st->beh.factory]->AddRef();
- engine->scriptFunctions[st->beh.construct]->AddRef();
- for( asUINT i = 1; i < st->beh.operators.GetLength(); i += 2 )
- engine->scriptFunctions[st->beh.operators[i]]->AddRef();
- return 0;
- }
- int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file)
- {
- asCScriptNode *n = node->firstChild;
- asCString name(&file->code[n->tokenPos], n->tokenLength);
- bool isShared = false;
- if( name == SHARED_TOKEN )
- {
- isShared = true;
- n = n->next;
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
- }
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- CheckNameConflict(name.AddressOf(), n, file);
- sClassDeclaration *decl = asNEW(sClassDeclaration);
- interfaceDeclarations.PushLast(decl);
- decl->name = name;
- decl->script = file;
- decl->node = node;
- // If this type is shared and there already exist another shared
- // type of the same name, then that one should be used instead of
- // creating a new one.
- if( isShared )
- {
- for( asUINT n = 0; n < engine->classTypes.GetLength(); n++ )
- {
- asCObjectType *st = engine->classTypes[n];
- if( st &&
- st->IsShared() &&
- st->name == name &&
- st->IsInterface() )
- {
- // We'll use the existing type
- decl->isExistingShared = true;
- decl->objType = st;
- module->classTypes.PushLast(st);
- st->AddRef();
- return 0;
- }
- }
- }
- // Register the object type for the interface
- asCObjectType *st = asNEW(asCObjectType)(engine);
- st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT;
- if( isShared )
- st->flags |= asOBJ_SHARED;
- st->size = 0; // Cannot be instanciated
- st->name = name;
- module->classTypes.PushLast(st);
- engine->classTypes.PushLast(st);
- st->AddRef();
- decl->objType = st;
- // Use the default script class behaviours
- st->beh.construct = 0;
- st->beh.addref = engine->scriptTypeBehaviours.beh.addref;
- engine->scriptFunctions[st->beh.addref]->AddRef();
- st->beh.release = engine->scriptTypeBehaviours.beh.release;
- engine->scriptFunctions[st->beh.release]->AddRef();
- st->beh.copy = 0;
- return 0;
- }
- void asCBuilder::CompileGlobalVariables()
- {
- bool compileSucceeded = true;
- // Store state of compilation (errors, warning, output)
- int currNumErrors = numErrors;
- int currNumWarnings = numWarnings;
- // Backup the original message stream
- bool msgCallback = engine->msgCallback;
- asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc;
- void *msgCallbackObj = engine->msgCallbackObj;
- // Set the new temporary message stream
- asCOutputBuffer outBuffer;
- engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL);
- asCOutputBuffer finalOutput;
- asCScriptFunction *initFunc = 0;
- asCArray<asCGlobalProperty*> initOrder;
- // We first try to compile all the primitive global variables, and only after that
- // compile the non-primitive global variables. This permits the constructors
- // for the complex types to use the already initialized variables of primitive
- // type. Note, we currently don't know which global variables are used in the
- // constructors, so we cannot guarantee that variables of complex types are
- // initialized in the correct order, so we won't reorder those.
- bool compilingPrimitives = true;
- // Compile each global variable
- while( compileSucceeded )
- {
- compileSucceeded = false;
- int accumErrors = 0;
- int accumWarnings = 0;
- // Restore state of compilation
- finalOutput.Clear();
- for( asUINT n = 0; n < globVariables.GetLength(); n++ )
- {
- sGlobalVariableDescription *gvar = globVariables[n];
- if( gvar->isCompiled )
- continue;
- asCByteCode init(engine);
- numWarnings = 0;
- numErrors = 0;
- outBuffer.Clear();
- // Skip this for now if we're not compiling complex types yet
- if( compilingPrimitives && !gvar->datatype.IsPrimitive() )
- continue;
- if( gvar->nextNode )
- {
- int r, c;
- gvar->script->ConvertPosToRowCol(gvar->nextNode->tokenPos, &r, &c);
- asCString str = gvar->datatype.Format();
- str += " " + gvar->name;
- str.Format(TXT_COMPILING_s, str.AddressOf());
- WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), r, c, true);
- }
- if( gvar->isEnumValue )
- {
- int r;
- if( gvar->nextNode )
- {
- asCCompiler comp(engine);
- asCScriptFunction func(engine, module, asFUNC_DUMMY);
- // Temporarily switch the type of the variable to int so it can be compiled properly
- asCDataType saveType;
- saveType = gvar->datatype;
- gvar->datatype = asCDataType::CreatePrimitive(ttInt, true);
- r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar, &func);
- gvar->datatype = saveType;
- }
- else
- {
- r = 0;
- // When there is no assignment the value is the last + 1
- int enumVal = 0;
- if( n > 0 )
- {
- sGlobalVariableDescription *gvar2 = globVariables[n-1];
- if( gvar2->datatype == gvar->datatype )
- {
- // The integer value is stored in the lower bytes
- enumVal = (*(int*)&gvar2->constantValue) + 1;
- if( !gvar2->isCompiled )
- {
- // TODO: Need to get the correct script position
- int row, col;
- gvar->script->ConvertPosToRowCol(0, &row, &col);
- asCString str = gvar->datatype.Format();
- str += " " + gvar->name;
- str.Format(TXT_COMPILING_s, str.AddressOf());
- WriteInfo(gvar->script->name.AddressOf(), str.AddressOf(), row, col, true);
- str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, gvar2->name.AddressOf());
- WriteError(gvar->script->name.AddressOf(), str.AddressOf(), row, col);
- r = -1;
- }
- }
- }
- // The integer value is stored in the lower bytes
- *(int*)&gvar->constantValue = enumVal;
- }
- if( r >= 0 )
- {
- // Set the value as compiled
- gvar->isCompiled = true;
- compileSucceeded = true;
- }
- }
- else
- {
- // Compile the global variable
- initFunc = asNEW(asCScriptFunction)(engine, module, asFUNC_DUMMY);
- asCCompiler comp(engine);
- int r = comp.CompileGlobalVariable(this, gvar->script, gvar->nextNode, gvar, initFunc);
- if( r >= 0 )
- {
- // Compilation succeeded
- gvar->isCompiled = true;
- compileSucceeded = true;
- }
- else
- {
- // Compilation failed
- asDELETE(initFunc, asCScriptFunction);
- initFunc = 0;
- }
- }
- if( gvar->isCompiled )
- {
- // Add warnings for this constant to the total build
- if( numWarnings )
- {
- currNumWarnings += numWarnings;
- if( msgCallback )
- outBuffer.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
- }
- // Determine order of variable initializations
- if( gvar->property && !gvar->isEnumValue )
- initOrder.PushLast(gvar->property);
- // Does the function contain more than just a SUSPEND followed by a RET instruction?
- if( initFunc && initFunc->byteCode.GetLength() > 2 )
- {
- // Create the init function for this variable
- initFunc->id = engine->GetNextScriptFunctionId();
- engine->SetScriptFunction(initFunc);
- // Finalize the init function for this variable
- initFunc->funcType = asFUNC_SCRIPT;
- initFunc->returnType = asCDataType::CreatePrimitive(ttVoid, false);
- initFunc->scriptSectionIdx = engine->GetScriptSectionNameIndex(gvar->script->name.AddressOf());
- // Notify the GC of the new script function
- engine->gc.AddScriptObjectToGC(initFunc, &engine->functionBehaviours);
- gvar->property->SetInitFunc(initFunc);
- initFunc->Release();
- initFunc = 0;
- }
- else if( initFunc )
- {
- // Destroy the function as it won't be used
- asDELETE(initFunc, asCScriptFunction);
- initFunc = 0;
- }
- // Convert enums to true enum values, so subsequent compilations can access it as an enum
- if( gvar->isEnumValue )
- {
- asCObjectType *objectType = gvar->datatype.GetObjectType();
- asASSERT(NULL != objectType);
- asSEnumValue *e = asNEW(asSEnumValue);
- e->name = gvar->name;
- e->value = *(int*)&gvar->constantValue;
- objectType->enumValues.PushLast(e);
- }
- }
- else
- {
- // Add output to final output
- finalOutput.Append(outBuffer);
- accumErrors += numErrors;
- accumWarnings += numWarnings;
- }
- preMessage.isSet = false;
- }
- if( !compileSucceeded )
- {
- if( compilingPrimitives )
- {
- // No more primitives could be compiled, so
- // switch to compiling the complex variables
- compilingPrimitives = false;
- compileSucceeded = true;
- }
- else
- {
- // No more variables can be compiled
- // Add errors and warnings to total build
- currNumWarnings += accumWarnings;
- currNumErrors += accumErrors;
- if( msgCallback )
- finalOutput.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj);
- }
- }
- }
- // Restore states
- engine->msgCallback = msgCallback;
- engine->msgCallbackFunc = msgCallbackFunc;
- engine->msgCallbackObj = msgCallbackObj;
- numWarnings = currNumWarnings;
- numErrors = currNumErrors;
- // Set the correct order of initialization
- if( numErrors == 0 )
- {
- // If the length of the arrays are not the same, then this is the compilation
- // of a single variable, in which case the initialization order of the previous
- // variables must be preserved.
- if( module->scriptGlobals.GetLength() == initOrder.GetLength() )
- module->scriptGlobals = initOrder;
- }
- // Delete the enum expressions
- for( asUINT n = 0; n < globVariables.GetLength(); n++ )
- {
- sGlobalVariableDescription *gvar = globVariables[n];
- if( gvar->isEnumValue )
- {
- // Destroy the gvar property
- if( gvar->nextNode )
- {
- gvar->nextNode->Destroy(engine);
- gvar->nextNode = 0;
- }
- if( gvar->property )
- {
- asDELETE(gvar->property, asCGlobalProperty);
- gvar->property = 0;
- }
- asDELETE(gvar, sGlobalVariableDescription);
- globVariables[n] = 0;
- }
- }
- }
- void asCBuilder::CompileClasses()
- {
- asUINT n;
- asCArray<sClassDeclaration*> toValidate((int)classDeclarations.GetLength());
- // Determine class inheritances and interfaces
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- asCScriptCode *file = decl->script;
- // Find the base class that this class inherits from
- bool multipleInheritance = false;
- asCScriptNode *node = decl->node->firstChild->next;
- if( decl->objType->IsShared() )
- {
- // Skip the keyword 'shared'
- node = node->next;
- }
- while( node && node->nodeType == snIdentifier )
- {
- // Get the interface name from the node
- asCString name(&file->code[node->tokenPos], node->tokenLength);
- // Find the object type for the interface
- asCObjectType *objType = GetObjectType(name.AddressOf());
- if( objType == 0 )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, name.AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- }
- else if( !(objType->flags & asOBJ_SCRIPT_OBJECT) )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_CANNOT_INHERIT_FROM_s, objType->name.AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- }
- else if( objType->size != 0 )
- {
- // The class inherits from another script class
- if( !decl->isExistingShared && decl->objType->derivedFrom != 0 )
- {
- if( !multipleInheritance )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, r, c);
- multipleInheritance = true;
- }
- }
- else
- {
- // Make sure none of the base classes inherit from this one
- asCObjectType *base = objType;
- bool error = false;
- while( base != 0 )
- {
- if( base == decl->objType )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_CANNOT_INHERIT_FROM_SELF, r, c);
- error = true;
- break;
- }
- base = base->derivedFrom;
- }
- if( !error )
- {
- // A shared type may only inherit from other shared types
- if( (decl->objType->IsShared()) && !(objType->IsShared()) )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s, objType->name.AddressOf());
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- error = true;
- }
- }
- if( !error )
- {
- if( decl->isExistingShared )
- {
- // Verify that the base class is the same as the original shared type
- if( decl->objType->derivedFrom != objType )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_SHARED_DOESNT_MATCH_ORIGINAL, r, c);
- }
- }
- else
- {
- // Set the base class
- decl->objType->derivedFrom = objType;
- objType->AddRef();
- }
- }
- }
- }
- else
- {
- // The class implements an interface
- if( !decl->isExistingShared && decl->objType->Implements(objType) )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, objType->GetName());
- WriteWarning(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
- else
- {
- // A shared type may only implement from shared interfaces
- if( (decl->objType->IsShared()) && !(objType->IsShared()) )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->name.AddressOf());
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
- else
- {
- if( decl->isExistingShared )
- {
- // Verify that the original implements the same interface
- if( !decl->objType->Implements(objType) )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_SHARED_DOESNT_MATCH_ORIGINAL, r, c);
- }
- }
- else
- {
- decl->objType->interfaces.PushLast(objType);
- }
- }
- }
- }
- node = node->next;
- }
- }
- // Order class declarations so that base classes are compiled before derived classes.
- // This will allow the derived classes to copy properties and methods in the next step.
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- asCObjectType *derived = decl->objType;
- asCObjectType *base = derived->derivedFrom;
- if( base == 0 ) continue;
- // If the base class is found after the derived class, then move the derived class to the end of the list
- for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ )
- {
- sClassDeclaration *declBase = classDeclarations[m];
- if( base == declBase->objType )
- {
- classDeclarations.RemoveIndex(n);
- classDeclarations.PushLast(decl);
- // Decrease index so that we don't skip an entry
- n--;
- break;
- }
- }
- }
- // Go through each of the classes and register the object type descriptions
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- if( decl->isExistingShared )
- {
- // TODO: shared: Should really validate against original
- continue;
- }
- // Add all properties and methods from the base class
- if( decl->objType->derivedFrom )
- {
- asCObjectType *baseType = decl->objType->derivedFrom;
- // The derived class inherits all interfaces from the base class
- for( unsigned int n = 0; n < baseType->interfaces.GetLength(); n++ )
- {
- if( !decl->objType->Implements(baseType->interfaces[n]) )
- {
- decl->objType->interfaces.PushLast(baseType->interfaces[n]);
- }
- else
- {
- // Warn if derived class already implements the interface
- int r, c;
- decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_INTERFACE_s_ALREADY_IMPLEMENTED, baseType->interfaces[n]->GetName());
- WriteWarning(decl->script->name.AddressOf(), msg.AddressOf(), r, c);
- }
- }
- // TODO: Need to check for name conflict with new class methods
- // Copy properties from base class to derived class
- for( asUINT p = 0; p < baseType->properties.GetLength(); p++ )
- {
- asCObjectProperty *prop = AddPropertyToClass(decl, baseType->properties[p]->name, baseType->properties[p]->type, baseType->properties[p]->isPrivate);
- // The properties must maintain the same offset
- asASSERT(prop && prop->byteOffset == baseType->properties[p]->byteOffset); UNUSED_VAR(prop);
- }
- // Copy methods from base class to derived class
- for( asUINT m = 0; m < baseType->methods.GetLength(); m++ )
- {
- // If the derived class implements the same method, then don't add the base class' method
- asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]);
- asCScriptFunction *derivedFunc = 0;
- bool found = false;
- for( asUINT d = 0; d < decl->objType->methods.GetLength(); d++ )
- {
- derivedFunc = GetFunctionDescription(decl->objType->methods[d]);
- if( derivedFunc->IsSignatureEqual(baseFunc) )
- {
- // Move the function from the methods array to the virtualFunctionTable
- decl->objType->methods.RemoveIndex(d);
- decl->objType->virtualFunctionTable.PushLast(derivedFunc);
- found = true;
- break;
- }
- }
- if( !found )
- {
- // Push the base class function on the virtual function table
- decl->objType->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]);
- baseType->virtualFunctionTable[m]->AddRef();
- }
- decl->objType->methods.PushLast(baseType->methods[m]);
- engine->scriptFunctions[baseType->methods[m]]->AddRef();
- }
- }
- // Move this class' methods into the virtual function table
- for( asUINT m = 0; m < decl->objType->methods.GetLength(); m++ )
- {
- asCScriptFunction *func = GetFunctionDescription(decl->objType->methods[m]);
- if( func->funcType != asFUNC_VIRTUAL )
- {
- // Move the reference from the method list to the virtual function list
- decl->objType->methods.RemoveIndex(m);
- decl->objType->virtualFunctionTable.PushLast(func);
- // Substitute the function description in the method list for a virtual method
- // Make sure the methods are in the same order as the virtual function table
- decl->objType->methods.PushLast(CreateVirtualFunction(func, (int)decl->objType->virtualFunctionTable.GetLength() - 1));
- m--;
- }
- }
- // Enumerate each of the declared properties
- asCScriptNode *node = decl->node->firstChild->next;
- // Skip list of classes and interfaces
- while( node && node->nodeType == snIdentifier )
- node = node->next;
- while( node )
- {
- if( node->nodeType == snDeclaration )
- {
- bool isPrivate = false;
- if( node->firstChild && node->firstChild->tokenType == ttPrivate )
- isPrivate = true;
- asCScriptCode *file = decl->script;
- asCDataType dt = CreateDataTypeFromNode(isPrivate ? node->firstChild->next : node->firstChild, file);
- asCString name(&file->code[node->lastChild->tokenPos], node->lastChild->tokenLength);
- if( decl->objType->IsShared() && dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
- if( dt.IsReadOnly() )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_PROPERTY_CANT_BE_CONST, r, c);
- }
- CheckNameConflictMember(decl->objType, name.AddressOf(), node->lastChild, file, true);
- AddPropertyToClass(decl, name, dt, isPrivate, file, node);
- }
- else
- asASSERT(false);
- node = node->next;
- }
- toValidate.PushLast(decl);
- }
- // Verify that all interface methods are implemented in the classes
- // We do this here so the base class' methods have already been inherited
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- if( decl->isExistingShared ) continue;
- for( asUINT m = 0; m < decl->objType->interfaces.GetLength(); m++ )
- {
- asCObjectType *objType = decl->objType->interfaces[m];
- for( asUINT i = 0; i < objType->methods.GetLength(); i++ )
- {
- if( !DoesMethodExist(decl->objType, objType->methods[i]) )
- {
- int r, c;
- decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_MISSING_IMPLEMENTATION_OF_s,
- engine->GetFunctionDeclaration(objType->methods[i]).AddressOf());
- WriteError(decl->script->name.AddressOf(), str.AddressOf(), r, c);
- }
- }
- }
- }
- // Verify that the declared structures are valid, e.g. that the structure
- // doesn't contain a member of its own type directly or indirectly
- while( toValidate.GetLength() > 0 )
- {
- asUINT numClasses = (asUINT)toValidate.GetLength();
- asCArray<sClassDeclaration*> toValidateNext((int)toValidate.GetLength());
- while( toValidate.GetLength() > 0 )
- {
- sClassDeclaration *decl = toValidate[toValidate.GetLength()-1];
- int validState = 1;
- for( asUINT n = 0; n < decl->objType->properties.GetLength(); n++ )
- {
- // A valid structure is one that uses only primitives or other valid objects
- asCObjectProperty *prop = decl->objType->properties[n];
- asCDataType dt = prop->type;
- if( dt.IsTemplate() )
- {
- asCDataType sub = dt;
- while( sub.IsTemplate() && !sub.IsObjectHandle() )
- sub = sub.GetSubType();
- dt = sub;
- }
- if( dt.IsObject() && !dt.IsObjectHandle() )
- {
- // Find the class declaration
- sClassDeclaration *pdecl = 0;
- for( asUINT p = 0; p < classDeclarations.GetLength(); p++ )
- {
- if( classDeclarations[p]->objType == dt.GetObjectType() )
- {
- pdecl = classDeclarations[p];
- break;
- }
- }
- if( pdecl )
- {
- if( pdecl->objType == decl->objType )
- {
- int r, c;
- decl->script->ConvertPosToRowCol(decl->node->tokenPos, &r, &c);
- WriteError(decl->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
- validState = 2;
- break;
- }
- else if( pdecl->validState != 1 )
- {
- validState = pdecl->validState;
- break;
- }
- }
- }
- }
- if( validState == 1 )
- {
- decl->validState = 1;
- toValidate.PopLast();
- }
- else if( validState == 2 )
- {
- decl->validState = 2;
- toValidate.PopLast();
- }
- else
- {
- toValidateNext.PushLast(toValidate.PopLast());
- }
- }
- toValidate = toValidateNext;
- toValidateNext.SetLength(0);
- if( numClasses == toValidate.GetLength() )
- {
- int r, c;
- toValidate[0]->script->ConvertPosToRowCol(toValidate[0]->node->tokenPos, &r, &c);
- WriteError(toValidate[0]->script->name.AddressOf(), TXT_ILLEGAL_MEMBER_TYPE, r, c);
- break;
- }
- }
- if( numErrors > 0 ) return;
- // Urho3D: disable garbage collection from script classes
- /*
- // Verify potential circular references
- for( n = 0; n < classDeclarations.GetLength(); n++ )
- {
- sClassDeclaration *decl = classDeclarations[n];
- if( decl->isExistingShared ) continue;
- asCObjectType *ot = decl->objType;
- // Is there some path in which this structure is involved in circular references?
- for( asUINT p = 0; p < ot->properties.GetLength(); p++ )
- {
- asCDataType dt = ot->properties[p]->type;
- if( dt.IsObject() )
- {
- if( dt.IsObjectHandle() )
- {
- // TODO: optimize: If it is known that the handle can't be involved in a circular reference
- // then this object doesn't need to be marked as garbage collected.
- // - The application could set a flag when registering the object.
- // - The script classes can be marked as final, then the compiler will
- // be able to determine whether the class is garbage collected or not.
- ot->flags |= asOBJ_GC;
- break;
- }
- else if( dt.GetObjectType()->flags & asOBJ_GC )
- {
- // TODO: optimize: Just because the member type is a potential circle doesn't mean that this one is
- // Only if the object is of a type that can reference this type, either directly or indirectly
- ot->flags |= asOBJ_GC;
- break;
- }
- }
- }
- }
- */
- }
- int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx)
- {
- asCScriptFunction *vf = asNEW(asCScriptFunction)(engine, module, asFUNC_VIRTUAL);
- vf->funcType = asFUNC_VIRTUAL;
- vf->name = func->name;
- vf->returnType = func->returnType;
- vf->parameterTypes = func->parameterTypes;
- vf->inOutFlags = func->inOutFlags;
- vf->id = engine->GetNextScriptFunctionId();
- vf->scriptSectionIdx = func->scriptSectionIdx;
- vf->isReadOnly = func->isReadOnly;
- vf->objectType = func->objectType;
- vf->signatureId = func->signatureId;
- vf->isPrivate = func->isPrivate;
- vf->vfTableIdx = idx;
- vf->defaultArgs = func->defaultArgs;
- // Copy the default arg strings to avoid multiple deletes on the same object
- for( asUINT n = 0; n < vf->defaultArgs.GetLength(); n++ )
- if( vf->defaultArgs[n] )
- vf->defaultArgs[n] = asNEW(asCString)(*vf->defaultArgs[n]);
- module->AddScriptFunction(vf);
- // Add a dummy to the builder so that it doesn't mix up function ids
- functions.PushLast(0);
- return vf->id;
- }
- asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, bool isPrivate, asCScriptCode *file, asCScriptNode *node)
- {
- if( !dt.CanBeInstanciated() )
- {
- if( file && node )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- }
- return 0;
- }
- return decl->objType->AddPropertyToClass(name, dt, isPrivate);
- }
- bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId)
- {
- asCScriptFunction *method = GetFunctionDescription(methodId);
- for( asUINT n = 0; n < objType->methods.GetLength(); n++ )
- {
- asCScriptFunction *m = GetFunctionDescription(objType->methods[n]);
- if( m->name != method->name ) continue;
- if( m->returnType != method->returnType ) continue;
- if( m->isReadOnly != method->isReadOnly ) continue;
- if( m->parameterTypes != method->parameterTypes ) continue;
- if( m->inOutFlags != method->inOutFlags ) continue;
- return true;
- }
- return false;
- }
- void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file)
- {
- int funcId = engine->GetNextScriptFunctionId();
- asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false);
- asCArray<asCDataType> parameterTypes;
- asCArray<asETypeModifiers> inOutFlags;
- asCArray<asCString *> defaultArgs;
- // Add the script function
- module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false, objType);
- // Set it as default constructor
- if( objType->beh.construct )
- engine->scriptFunctions[objType->beh.construct]->Release();
- objType->beh.construct = funcId;
- objType->beh.constructors[0] = funcId;
- engine->scriptFunctions[funcId]->AddRef();
- // The bytecode for the default constructor will be generated
- // only after the potential inheritance has been established
- sFunctionDescription *func = asNEW(sFunctionDescription);
- functions.PushLast(func);
- func->script = file;
- func->node = 0;
- func->name = objType->name;
- func->objType = objType;
- func->funcId = funcId;
- // Add a default factory as well
- funcId = engine->GetNextScriptFunctionId();
- if( objType->beh.factory )
- engine->scriptFunctions[objType->beh.factory]->Release();
- objType->beh.factory = funcId;
- objType->beh.factories[0] = funcId;
- returnType = asCDataType::CreateObjectHandle(objType, false);
- module->AddScriptFunction(file->idx, funcId, objType->name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
- functions.PushLast(0);
- asCCompiler compiler(engine);
- compiler.CompileFactory(this, file, engine->scriptFunctions[funcId]);
- engine->scriptFunctions[funcId]->AddRef();
- }
- int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file)
- {
- // Grab the name of the enumeration
- asCScriptNode *tmp = node->firstChild;
- asASSERT(snDataType == tmp->nodeType);
- asCString name;
- asASSERT(snIdentifier == tmp->firstChild->nodeType);
- name.Assign(&file->code[tmp->firstChild->tokenPos], tmp->firstChild->tokenLength);
- // Check the name and add the enum
- int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file);
- if( asSUCCESS == r )
- {
- asCObjectType *st;
- asCDataType dataType;
- st = asNEW(asCObjectType)(engine);
- dataType.CreatePrimitive(ttInt, false);
- st->flags = asOBJ_ENUM;
- st->size = 4;
- st->name = name;
- module->enumTypes.PushLast(st);
- st->AddRef();
- engine->classTypes.PushLast(st);
- // Store the location of this declaration for reference in name collisions
- sClassDeclaration *decl = asNEW(sClassDeclaration);
- decl->name = name;
- decl->script = file;
- decl->objType = st;
- namedTypeDeclarations.PushLast(decl);
- asCDataType type = CreateDataTypeFromNode(tmp, file);
- asASSERT(!type.IsReference());
- tmp = tmp->next;
- while( tmp )
- {
- asASSERT(snIdentifier == tmp->nodeType);
- asCString name(&file->code[tmp->tokenPos], tmp->tokenLength);
- // Check for name conflict errors with other values in the enum
- r = 0;
- for( size_t n = globVariables.GetLength(); n-- > 0; )
- {
- sGlobalVariableDescription *gvar = globVariables[n];
- if( gvar->datatype != type )
- break;
- if( gvar->name == name )
- {
- r = asNAME_TAKEN;
- break;
- }
- }
- if( asSUCCESS != r )
- {
- int r, c;
- file->ConvertPosToRowCol(tmp->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- tmp = tmp->next;
- if( tmp && tmp->nodeType == snAssignment )
- tmp = tmp->next;
- continue;
- }
- // check for assignment
- asCScriptNode *asnNode = tmp->next;
- if( asnNode && snAssignment == asnNode->nodeType )
- asnNode->DisconnectParent();
- else
- asnNode = 0;
- // Create the global variable description so the enum value can be evaluated
- sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription);
- globVariables.PushLast(gvar);
- gvar->script = file;
- gvar->idNode = 0;
- gvar->nextNode = asnNode;
- gvar->name = name;
- gvar->datatype = type;
- // No need to allocate space on the global memory stack since the values are stored in the asCObjectType
- gvar->index = 0;
- gvar->isCompiled = false;
- gvar->isPureConstant = true;
- gvar->isEnumValue = true;
- gvar->constantValue = 0xdeadbeef;
- // Allocate dummy property so we can compile the value.
- // This will be removed later on so we don't add it to the engine.
- gvar->property = asNEW(asCGlobalProperty);
- gvar->property->name = name;
- gvar->property->type = gvar->datatype;
- gvar->property->id = 0;
- tmp = tmp->next;
- }
- }
- node->Destroy(engine);
- return r;
- }
- int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file)
- {
- // Get the native data type
- asCScriptNode *tmp = node->firstChild;
- asASSERT(NULL != tmp && snDataType == tmp->nodeType);
- asCDataType dataType;
- dataType.CreatePrimitive(tmp->tokenType, false);
- dataType.SetTokenType(tmp->tokenType);
- tmp = tmp->next;
- // Grab the name of the typedef
- asASSERT(NULL != tmp && NULL == tmp->next);
- asCString name;
- name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength);
- // If the name is not already in use add it
- int r = CheckNameConflict(name.AddressOf(), tmp, file);
- if( asSUCCESS == r )
- {
- // Create the new type
- asCObjectType *st = asNEW(asCObjectType)(engine);
- st->flags = asOBJ_TYPEDEF;
- st->size = dataType.GetSizeInMemoryBytes();
- st->name = name;
- st->templateSubType = dataType;
- st->AddRef();
- module->typeDefs.PushLast(st);
- engine->classTypes.PushLast(st);
- // Store the location of this declaration for reference in name collisions
- sClassDeclaration *decl = asNEW(sClassDeclaration);
- decl->name = name;
- decl->script = file;
- decl->objType = st;
- namedTypeDeclarations.PushLast(decl);
- }
- node->Destroy(engine);
- if( r < 0 )
- {
- engine->ConfigError(r);
- }
- return 0;
- }
- void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray<asCDataType> ¶meterTypes, asCArray<asETypeModifiers> &inOutFlags, asCArray<asCString *> &defaultArgs, bool &isConstMethod, bool &isConstructor, bool &isDestructor, bool &isPrivate)
- {
- node = node->firstChild;
- // Is the function a private class method?
- isPrivate = false;
- if( node->tokenType == ttPrivate )
- {
- isPrivate = true;
- node = node->next;
- }
- // Find the name
- isConstructor = false;
- isDestructor = false;
- asCScriptNode *n = 0;
- if( node->nodeType == snDataType )
- n = node->next->next;
- else
- {
- // If the first node is a ~ token, then we know it is a destructor
- if( node->tokenType == ttBitNot )
- {
- n = node->next;
- isDestructor = true;
- }
- else
- {
- n = node;
- isConstructor = true;
- }
- }
- name.Assign(&file->code[n->tokenPos], n->tokenLength);
- // Initialize a script function object for registration
- if( !isConstructor && !isDestructor )
- {
- returnType = CreateDataTypeFromNode(node, file);
- returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0);
- }
- else
- returnType = asCDataType::CreatePrimitive(ttVoid, false);
- // Is this a const method?
- if( objType && n->next->next && n->next->next->tokenType == ttConst )
- isConstMethod = true;
- else
- isConstMethod = false;
- // Count the number of parameters
- int count = 0;
- asCScriptNode *c = n->next->firstChild;
- while( c )
- {
- count++;
- c = c->next->next;
- if( c && c->nodeType == snIdentifier )
- c = c->next;
- if( c && c->nodeType == snExpression )
- c = c->next;
- }
- // Get the parameter types
- parameterTypes.Allocate(count, false);
- inOutFlags.Allocate(count, false);
- defaultArgs.Allocate(count, false);
- n = n->next->firstChild;
- while( n )
- {
- asETypeModifiers inOutFlag;
- asCDataType type = CreateDataTypeFromNode(n, file);
- type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
- // Store the parameter type
- parameterTypes.PushLast(type);
- inOutFlags.PushLast(inOutFlag);
- // Move to next parameter
- n = n->next->next;
- if( n && n->nodeType == snIdentifier )
- n = n->next;
-
- if( n && n->nodeType == snExpression )
- {
- // Strip out white space and comments to better share the string
- asCString *defaultArgStr = asNEW(asCString);
- *defaultArgStr = GetCleanExpressionString(n, file);
- defaultArgs.PushLast(defaultArgStr);
- n = n->next;
- }
- else
- defaultArgs.PushLast(0);
- }
- }
- asCString asCBuilder::GetCleanExpressionString(asCScriptNode *node, asCScriptCode *file)
- {
- asASSERT(node && node->nodeType == snExpression);
- asCString str;
- str.Assign(file->code + node->tokenPos, node->tokenLength);
- asCString cleanStr;
- for( asUINT n = 0; n < str.GetLength(); )
- {
- int len;
- asETokenClass tok = engine->ParseToken(str.AddressOf() + n, str.GetLength() - n, &len);
- if( tok != asTC_COMMENT && tok != asTC_WHITESPACE )
- {
- if( cleanStr.GetLength() ) cleanStr += " ";
- cleanStr.Concatenate(str.AddressOf() + n, len);
- }
- n += len;
- }
- return cleanStr;
- }
- int asCBuilder::RegisterScriptFunction(int funcId, asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction)
- {
- asCString name;
- asCDataType returnType;
- asCArray<asCDataType> parameterTypes;
- asCArray<asETypeModifiers> inOutFlags;
- asCArray<asCString *> defaultArgs;
- bool isConstMethod;
- bool isConstructor;
- bool isDestructor;
- bool isPrivate;
- GetParsedFunctionDetails(node, file, objType, name, returnType, parameterTypes, inOutFlags, defaultArgs, isConstMethod, isConstructor, isDestructor, isPrivate);
- // Check for name conflicts
- if( !isConstructor && !isDestructor )
- {
- if( objType )
- {
- CheckNameConflictMember(objType, name.AddressOf(), node, file, false);
- if( name == objType->name )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, r, c);
- }
- }
- else
- CheckNameConflict(name.AddressOf(), node, file);
- }
- else
- {
- // Verify that the name of the constructor/destructor is the same as the class
- if( name != objType->name )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_CONSTRUCTOR_NAME_ERROR, r, c);
- }
- if( isDestructor )
- name = "~" + name;
- }
- if( !isInterface )
- {
- sFunctionDescription *func = asNEW(sFunctionDescription);
- functions.PushLast(func);
- func->script = file;
- func->node = node;
- func->name = name;
- func->objType = objType;
- func->funcId = funcId;
- }
- // Destructors may not have any parameters
- if( isDestructor && parameterTypes.GetLength() > 0 )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, r, c);
- }
- // If class or interface is shared, then only shared types may be used in the method signature
- if( objType && objType->IsShared() )
- {
- asCObjectType *ot = returnType.GetObjectType();
- if( ot && !ot->IsShared() )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
-
- for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
- {
- asCObjectType *ot = parameterTypes[p].GetObjectType();
- if( ot && !ot->IsShared() )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- asCString msg;
- msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
- }
- }
- // TODO: Much of this can probably be reduced by using the IsSignatureEqual method
- // Check that the same function hasn't been registered already
- asCArray<int> funcs;
- GetFunctionDescriptions(name.AddressOf(), funcs);
- if( funcs.GetLength() )
- {
- for( asUINT n = 0; n < funcs.GetLength(); ++n )
- {
- asCScriptFunction *func = GetFunctionDescription(funcs[n]);
- if( parameterTypes.GetLength() == func->parameterTypes.GetLength() )
- {
- bool match = true;
- if( func->objectType != objType )
- {
- match = false;
- break;
- }
- for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
- {
- if( parameterTypes[p] != func->parameterTypes[p] )
- {
- match = false;
- break;
- }
- }
- if( match )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
- break;
- }
- }
- }
- }
- // Register the function
- module->AddScriptFunction(file->idx, funcId, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), isInterface, objType, isConstMethod, isGlobalFunction, isPrivate);
- // Make sure the default args are declared correctly
- ValidateDefaultArgs(file, node, engine->scriptFunctions[funcId]);
- if( objType )
- {
- engine->scriptFunctions[funcId]->AddRef();
- if( isConstructor )
- {
- int factoryId = engine->GetNextScriptFunctionId();
- if( parameterTypes.GetLength() == 0 )
- {
- // Overload the default constructor
- engine->scriptFunctions[objType->beh.construct]->Release();
- objType->beh.construct = funcId;
- objType->beh.constructors[0] = funcId;
- // Register the default factory as well
- engine->scriptFunctions[objType->beh.factory]->Release();
- objType->beh.factory = factoryId;
- objType->beh.factories[0] = factoryId;
- }
- else
- {
- objType->beh.constructors.PushLast(funcId);
- // Register the factory as well
- objType->beh.factories.PushLast(factoryId);
- }
- // We must copy the default arg strings to avoid deleting the same object multiple times
- for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
- if( defaultArgs[n] )
- defaultArgs[n] = asNEW(asCString)(*defaultArgs[n]);
- asCDataType dt = asCDataType::CreateObjectHandle(objType, false);
- module->AddScriptFunction(file->idx, factoryId, name.AddressOf(), dt, parameterTypes.AddressOf(), inOutFlags.AddressOf(), defaultArgs.AddressOf(), (asUINT)parameterTypes.GetLength(), false);
- // Add a dummy function to the module so that it doesn't mix up the fund Ids
- functions.PushLast(0);
- // Compile the factory immediately
- asCCompiler compiler(engine);
- compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]);
- engine->scriptFunctions[factoryId]->AddRef();
- }
- else if( isDestructor )
- objType->beh.destruct = funcId;
- else
- objType->methods.PushLast(funcId);
- }
- // We need to delete the node already if this is an interface method
- if( isInterface && node )
- {
- node->Destroy(engine);
- }
- return 0;
- }
- int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCScriptCode *file)
- {
- // Find name
- asCScriptNode *f = node->firstChild;
- asCScriptNode *n = f->firstChild->next->next;
- // Check for name conflicts
- asCString name(&file->code[n->tokenPos], n->tokenLength);
- CheckNameConflict(name.AddressOf(), n, file);
- // Initialize a script function object for registration
- asCDataType returnType;
- returnType = CreateDataTypeFromNode(f->firstChild, file);
- returnType = ModifyDataTypeFromNode(returnType, f->firstChild->next, file, 0, 0);
- // Count the parameters
- int count = 0;
- asCScriptNode *c = n->next->firstChild;
- while( c )
- {
- count++;
- c = c->next->next;
- if( c && c->nodeType == snIdentifier )
- c = c->next;
- }
- asCArray<asCDataType> parameterTypes(count);
- asCArray<asETypeModifiers> inOutFlags(count);
- n = n->next->firstChild;
- while( n )
- {
- asETypeModifiers inOutFlag;
- asCDataType type = CreateDataTypeFromNode(n, file);
- type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0);
- // Store the parameter type
- parameterTypes.PushLast(type);
- inOutFlags.PushLast(inOutFlag);
- if( type.GetTokenType() == ttVoid )
- {
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- asCString str;
- str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- break;
- }
- // Move to next parameter
- n = n->next->next;
- if( n && n->nodeType == snIdentifier )
- n = n->next;
- }
- // Check that the same function hasn't been registered already
- asCArray<int> funcs;
- GetFunctionDescriptions(name.AddressOf(), funcs);
- if( funcs.GetLength() )
- {
- for( asUINT n = 0; n < funcs.GetLength(); ++n )
- {
- asCScriptFunction *func = GetFunctionDescription(funcs[n]);
- if( parameterTypes.GetLength() == func->parameterTypes.GetLength() )
- {
- bool match = true;
- for( asUINT p = 0; p < parameterTypes.GetLength(); ++p )
- {
- if( parameterTypes[p] != func->parameterTypes[p] )
- {
- match = false;
- break;
- }
- }
- if( match )
- {
- int r, c;
- file->ConvertPosToRowCol(node->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_FUNCTION_ALREADY_EXIST, r, c);
- break;
- }
- }
- }
- }
- // Read the module name as well
- n = node->firstChild->next;
- asCString moduleName;
- moduleName.Assign(&file->code[n->tokenPos+1], n->tokenLength-2);
- node->Destroy(engine);
- // Register the function
- module->AddImportedFunction(importID, name.AddressOf(), returnType, parameterTypes.AddressOf(), inOutFlags.AddressOf(), (asUINT)parameterTypes.GetLength(), moduleName);
- return 0;
- }
- asCScriptFunction *asCBuilder::GetFunctionDescription(int id)
- {
- // TODO: import: This should be improved when the imported functions are removed
- // Get the description from the engine
- if( (id & 0xFFFF0000) == 0 )
- return engine->scriptFunctions[id];
- else
- return engine->importedFunctions[id & 0xFFFF]->importedFunctionSignature;
- }
- void asCBuilder::GetFunctionDescriptions(const char *name, asCArray<int> &funcs)
- {
- asUINT n;
- // TODO: optimize: Improve linear search
- for( n = 0; n < module->scriptFunctions.GetLength(); n++ )
- {
- if( module->scriptFunctions[n]->name == name &&
- module->scriptFunctions[n]->objectType == 0 )
- funcs.PushLast(module->scriptFunctions[n]->id);
- }
- // TODO: optimize: Improve linear search
- for( n = 0; n < module->bindInformations.GetLength(); n++ )
- {
- if( module->bindInformations[n]->importedFunctionSignature->name == name )
- funcs.PushLast(module->bindInformations[n]->importedFunctionSignature->id);
- }
- // TODO: optimize: Improve linear search
- // TODO: optimize: Use the registeredGlobalFunctions array instead
- for( n = 0; n < engine->scriptFunctions.GetLength(); n++ )
- {
- if( engine->scriptFunctions[n] &&
- engine->scriptFunctions[n]->funcType == asFUNC_SYSTEM &&
- engine->scriptFunctions[n]->objectType == 0 &&
- engine->scriptFunctions[n]->name == name )
- {
- // Verify if the module has access to the function
- if( module->accessMask & engine->scriptFunctions[n]->accessMask )
- {
- #ifdef AS_DEPRECATED
- // deprecated since 2011-10-04
- // Find the config group for the global function
- asCConfigGroup *group = engine->FindConfigGroupForFunction(engine->scriptFunctions[n]->id);
- if( !group || group->HasModuleAccess(module->name.AddressOf()) )
- #endif
- funcs.PushLast(engine->scriptFunctions[n]->id);
- }
- }
- }
- }
- void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray<int> &methods, bool objIsConst, const asCString &scope)
- {
- if( scope != "" )
- {
- // Find the base class with the specified scope
- while( objectType && objectType->name != scope )
- objectType = objectType->derivedFrom;
- // If the scope is not any of the base classes, then return no methods
- if( objectType == 0 )
- return;
- }
- // TODO: optimize: Improve linear search
- if( objIsConst )
- {
- // Only add const methods to the list
- for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
- {
- if( engine->scriptFunctions[objectType->methods[n]]->name == name &&
- engine->scriptFunctions[objectType->methods[n]]->isReadOnly )
- {
- // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
- if( scope == "" )
- methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
- else
- {
- asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
- asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
- methods.PushLast(realFunc->id);
- }
- }
- }
- }
- else
- {
- // TODO: Prefer non-const over const
- for( asUINT n = 0; n < objectType->methods.GetLength(); n++ )
- {
- if( engine->scriptFunctions[objectType->methods[n]]->name == name )
- {
- // When the scope is defined the returned methods should be the true methods, not the virtual method stubs
- if( scope == "" )
- methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id);
- else
- {
- asCScriptFunction *virtFunc = engine->scriptFunctions[objectType->methods[n]];
- asCScriptFunction *realFunc = objectType->virtualFunctionTable[virtFunc->vfTableIdx];
- methods.PushLast(realFunc->id);
- }
- }
- }
- }
- }
- void asCBuilder::WriteInfo(const char *scriptname, const char *message, int r, int c, bool pre)
- {
- // Need to store the pre message in a structure
- if( pre )
- {
- preMessage.isSet = true;
- preMessage.c = c;
- preMessage.r = r;
- preMessage.message = message;
- }
- else
- {
- preMessage.isSet = false;
- engine->WriteMessage(scriptname, r, c, asMSGTYPE_INFORMATION, message);
- }
- }
- void asCBuilder::WriteError(const char *scriptname, const char *message, int r, int c)
- {
- numErrors++;
- // Need to pass the preMessage first
- if( preMessage.isSet )
- WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
- engine->WriteMessage(scriptname, r, c, asMSGTYPE_ERROR, message);
- }
- void asCBuilder::WriteWarning(const char *scriptname, const char *message, int r, int c)
- {
- numWarnings++;
- // Need to pass the preMessage first
- if( preMessage.isSet )
- WriteInfo(scriptname, preMessage.message.AddressOf(), preMessage.r, preMessage.c, false);
- engine->WriteMessage(scriptname, r, c, asMSGTYPE_WARNING, message);
- }
- asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, bool acceptHandleForScope, asCObjectType *templateType)
- {
- asASSERT(node->nodeType == snDataType);
- asCDataType dt;
- asCScriptNode *n = node->firstChild;
- bool isConst = false;
- bool isImplicitHandle = false;
- if( n->tokenType == ttConst )
- {
- isConst = true;
- n = n->next;
- }
- if( n->tokenType == ttIdentifier )
- {
- asCString str;
- str.Assign(&file->code[n->tokenPos], n->tokenLength);
- asCObjectType *ot = 0;
- // If this is for a template type, then we must first determine if the
- // identifier matches any of the template subtypes
- // TODO: template: it should be possible to have more than one subtypes
- if( templateType && (templateType->flags & asOBJ_TEMPLATE) && str == templateType->templateSubType.GetObjectType()->name )
- ot = templateType->templateSubType.GetObjectType();
- if( ot == 0 )
- ot = GetObjectType(str.AddressOf());
-
- if( ot )
- {
- if( ot->flags & asOBJ_IMPLICIT_HANDLE )
- isImplicitHandle = true;
- // Make sure the module has access to the object type
- #ifdef AS_DEPRECATED
- // deprecated since 2011-10-04
- // Find the config group for the object type
- asCConfigGroup *group = engine->FindConfigGroupForObjectType(ot);
- if( !module || ((module->accessMask & ot->accessMask) && (!group || group->HasModuleAccess(module->name.AddressOf()))) )
- #else
- if( !module || (module->accessMask & ot->accessMask) )
- #endif
- {
- if(asOBJ_TYPEDEF == (ot->flags & asOBJ_TYPEDEF))
- {
- // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two)
- // Create primitive data type based on object flags
- dt = ot->templateSubType;
- dt.MakeReadOnly(isConst);
- }
- else
- {
- if( ot->flags & asOBJ_TEMPLATE )
- {
- n = n->next;
-
- // Check if the subtype is a type or the template's subtype
- // if it is the template's subtype then this is the actual template type,
- // orderwise it is a template instance.
- // Only do this for application registered interface, as the
- // scripts cannot implement templates.
- asCDataType subType = CreateDataTypeFromNode(n, file, false, module ? 0 : ot);
- if( subType.GetObjectType() != ot->templateSubType.GetObjectType() )
- {
- // This is a template instance
- // Need to find the correct object type
- asCObjectType *otInstance = engine->GetTemplateInstanceType(ot, subType);
- if( !otInstance )
- {
- asCString msg;
- msg.Format(TXT_CANNOT_INSTANCIATE_TEMPLATE_s_WITH_s, ot->name.AddressOf(), subType.Format().AddressOf());
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- }
- ot = otInstance;
- }
- }
- // Create object data type
- if( ot )
- dt = asCDataType::CreateObject(ot, isConst);
- else
- dt = asCDataType::CreatePrimitive(ttInt, isConst);
- }
- }
- else
- {
- asCString msg;
- msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf());
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- dt.SetTokenType(ttInt);
- }
- }
- else if( ot == 0 )
- {
- // It can still be a function definition
- asCScriptFunction *funcdef = GetFuncDef(str.AddressOf());
- if( funcdef )
- {
- dt = asCDataType::CreateFuncDef(funcdef);
- }
- else if( funcdef == 0 )
- {
- asCString msg;
- msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, (const char *)str.AddressOf());
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), msg.AddressOf(), r, c);
- dt = asCDataType::CreatePrimitive(ttInt, isConst);
- return dt;
- }
- }
- }
- else
- {
- // Create primitive data type
- dt = asCDataType::CreatePrimitive(n->tokenType, isConst);
- }
- // Determine array dimensions and object handles
- n = n->next;
- while( n && (n->tokenType == ttOpenBracket || n->tokenType == ttHandle) )
- {
- if( n->tokenType == ttOpenBracket )
- {
- // Make sure the sub type can be instanciated
- if( !dt.CanBeInstanciated() )
- {
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- asCString str;
- // TODO: Change to "Array sub type cannot be 'type'"
- str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
- WriteError(file->name.AddressOf(), str.AddressOf(), r, c);
- }
- // Make the type an array (or multidimensional array)
- if( dt.MakeArray(engine) < 0 )
- {
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_NO_DEFAULT_ARRAY_TYPE, r, c);
- break;
- }
- }
- else
- {
- // Make the type a handle
- if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
- {
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
- break;
- }
- }
- n = n->next;
- }
- if( isImplicitHandle )
- {
- // Make the type a handle
- if( dt.MakeHandle(true, acceptHandleForScope) < 0 )
- {
- int r, c;
- file->ConvertPosToRowCol(n->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_OBJECT_HANDLE_NOT_SUPPORTED, r, c);
- }
- }
- return dt;
- }
- asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle)
- {
- asCDataType dt = type;
- if( inOutFlags ) *inOutFlags = asTM_NONE;
- // Is the argument sent by reference?
- asCScriptNode *n = node->firstChild;
- if( n && n->tokenType == ttAmp )
- {
- dt.MakeReference(true);
- n = n->next;
- if( n )
- {
- if( inOutFlags )
- {
- if( n->tokenType == ttIn )
- *inOutFlags = asTM_INREF;
- else if( n->tokenType == ttOut )
- *inOutFlags = asTM_OUTREF;
- else if( n->tokenType == ttInOut )
- *inOutFlags = asTM_INOUTREF;
- else
- asASSERT(false);
- }
- n = n->next;
- }
- else
- {
- if( inOutFlags )
- *inOutFlags = asTM_INOUTREF; // ttInOut
- }
- if( !engine->ep.allowUnsafeReferences &&
- inOutFlags && *inOutFlags == asTM_INOUTREF )
- {
- // Verify that the base type support &inout parameter types
- if( !dt.IsObject() || dt.IsObjectHandle() || !dt.GetObjectType()->beh.addref || !dt.GetObjectType()->beh.release )
- {
- int r, c;
- file->ConvertPosToRowCol(node->firstChild->tokenPos, &r, &c);
- WriteError(file->name.AddressOf(), TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, r, c);
- }
- }
- }
- if( autoHandle ) *autoHandle = false;
- if( n && n->tokenType == ttPlus )
- {
- if( autoHandle ) *autoHandle = true;
- }
- return dt;
- }
- asCObjectType *asCBuilder::GetObjectType(const char *type)
- {
- asCObjectType *ot = engine->GetObjectType(type);
- if( !ot && module )
- ot = module->GetObjectType(type);
- return ot;
- }
- asCScriptFunction *asCBuilder::GetFuncDef(const char *type)
- {
- for( asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++ )
- {
- // TODO: access: Only return the definitions for the config groups that the module has access to
- if( engine->registeredFuncDefs[n]->name == type )
- {
- return engine->registeredFuncDefs[n];
- }
- }
- if( module )
- {
- for( asUINT n = 0; n < module->funcDefs.GetLength(); n++ )
- {
- if( module->funcDefs[n]->name == type )
- {
- return module->funcDefs[n];
- }
- }
- }
- return 0;
- }
- int asCBuilder::GetEnumValueFromObjectType(asCObjectType *objType, const char *name, asCDataType &outDt, asDWORD &outValue)
- {
- if( !objType || !(objType->flags & asOBJ_ENUM) )
- return 0;
- for( asUINT n = 0; n < objType->enumValues.GetLength(); ++n )
- {
- if( objType->enumValues[n]->name == name )
- {
- outDt = asCDataType::CreateObject(objType, true);
- outValue = objType->enumValues[n]->value;
- return 1;
- }
- }
- return 0;
- }
- int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue)
- {
- bool found = false;
- // Search all available enum types
- asUINT t;
- for( t = 0; t < engine->objectTypes.GetLength(); t++ )
- {
- asCObjectType *ot = engine->objectTypes[t];
- if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
- {
- if( !found )
- {
- found = true;
- }
- else
- {
- // Found more than one value in different enum types
- return 2;
- }
- }
- }
- for( t = 0; t < module->enumTypes.GetLength(); t++ )
- {
- asCObjectType *ot = module->enumTypes[t];
- if( GetEnumValueFromObjectType( ot, name, outDt, outValue ) )
- {
- if( !found )
- {
- found = true;
- }
- else
- {
- // Found more than one value in different enum types
- return 2;
- }
- }
- }
- if( found )
- return 1;
- // Didn't find any value
- return 0;
- }
- END_AS_NAMESPACE
|