| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093 |
- /*
- 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]
- */
- //
- // as_parser.cpp
- //
- // This class parses the script code and builds a tree for compilation
- //
- #include "as_config.h"
- #include "as_parser.h"
- #include "as_tokendef.h"
- #include "as_texts.h"
- #ifdef _MSC_VER
- #pragma warning(disable:4702) // unreachable code
- #endif
- BEGIN_AS_NAMESPACE
- asCParser::asCParser(asCBuilder *builder) : tokenizer(builder->engine)
- {
- this->builder = builder;
- this->engine = builder->engine;
- script = 0;
- scriptNode = 0;
- checkValidTypes = false;
- isParsingAppInterface = false;
- }
- asCParser::~asCParser()
- {
- Reset();
- }
- void asCParser::Reset()
- {
- errorWhileParsing = false;
- isSyntaxError = false;
- checkValidTypes = false;
- isParsingAppInterface = false;
- sourcePos = 0;
- if( scriptNode )
- {
- scriptNode->Destroy(engine);
- }
- scriptNode = 0;
- script = 0;
- }
- asCScriptNode *asCParser::GetScriptNode()
- {
- return scriptNode;
- }
- int asCParser::ParseScript(asCScriptCode *script)
- {
- Reset();
- this->script = script;
- scriptNode = ParseScript();
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- int asCParser::ParseFunctionDefinition(asCScriptCode *script)
- {
- Reset();
- // Set flag that permits ? as datatype for parameters
- isParsingAppInterface = true;
- this->script = script;
- scriptNode = ParseFunctionDefinition();
- // The declaration should end after the definition
- if( !isSyntaxError )
- {
- sToken t;
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEnd)).AddressOf(), &t);
- return -1;
- }
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- int asCParser::ParseExpression(asCScriptCode *script)
- {
- Reset();
- this->script = script;
- scriptNode = ParseExpression();
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- int asCParser::ParseDataType(asCScriptCode *script)
- {
- Reset();
- this->script = script;
- scriptNode = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
-
- scriptNode->AddChildLast(ParseType(true));
- if( isSyntaxError ) return -1;
- // The declaration should end after the type
- sToken t;
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEnd)).AddressOf(), &t);
- return -1;
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- // Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>'
- int asCParser::ParseTemplateDecl(asCScriptCode *script)
- {
- Reset();
- this->script = script;
- scriptNode = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined);
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- sToken t;
- GetToken(&t);
- if( t.type != ttLessThan )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttLessThan)).AddressOf(), &t);
- return -1;
- }
- // The class token is optional
- GetToken(&t);
- if( t.type != ttClass )
- RewindTo(&t);
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- GetToken(&t);
- if( t.type != ttGreaterThan )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttGreaterThan)).AddressOf(), &t);
- return -1;
- }
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEnd)).AddressOf(), &t);
- return -1;
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- int asCParser::ParsePropertyDeclaration(asCScriptCode *script)
- {
- Reset();
- this->script = script;
- scriptNode = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDeclaration);
- scriptNode->AddChildLast(ParseType(true));
- if( isSyntaxError ) return -1;
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- // The declaration should end after the identifier
- sToken t;
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEnd)).AddressOf(), &t);
- return -1;
- }
- return 0;
- }
- asCScriptNode *asCParser::ParseImport()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snImport);
- sToken t;
- GetToken(&t);
- if( t.type != ttImport )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttImport)).AddressOf(), &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- node->AddChildLast(ParseFunctionDefinition());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttIdentifier )
- {
- Error(ExpectedToken(FROM_TOKEN).AddressOf(), &t);
- return node;
- }
- asCString str;
- str.Assign(&script->code[t.pos], t.length);
- if( str != FROM_TOKEN )
- {
- Error(ExpectedToken(FROM_TOKEN).AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttStringConstant )
- {
- Error(TXT_EXPECTED_STRING, &t);
- return node;
- }
- asCScriptNode *mod = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snConstant);
- node->AddChildLast(mod);
- mod->SetToken(&t);
- mod->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEndStatement)).AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseFunctionDefinition()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFunction);
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseParameterList());
- if( isSyntaxError ) return node;
- // Parse an optional const after the function definition (used for object methods)
- sToken t1;
- GetToken(&t1);
- RewindTo(&t1);
- if( t1.type == ttConst )
- node->AddChildLast(ParseToken(ttConst));
- return node;
- }
- asCScriptNode *asCParser::ParseScript()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snScript);
- // Determine type of node
- sToken t1, t2;
- for(;;)
- {
- while( !isSyntaxError )
- {
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- if( t1.type == ttImport )
- node->AddChildLast(ParseImport());
- else if( t1.type == ttEnum )
- node->AddChildLast(ParseEnumeration()); // Handle enumerations
- else if( t1.type == ttTypedef )
- node->AddChildLast(ParseTypedef()); // Handle primitive typedefs
- else if( t1.type == ttClass || (t1.type == ttIdentifier && t2.type == ttClass) )
- node->AddChildLast(ParseClass());
- else if( t1.type == ttInterface || (t1.type == ttIdentifier && t2.type == ttInterface) )
- node->AddChildLast(ParseInterface());
- else if( t1.type == ttFuncDef )
- node->AddChildLast(ParseFuncDef());
- else if( t1.type == ttConst || IsDataType(t1) )
- {
- if( IsVarDecl() )
- node->AddChildLast(ParseGlobalVar());
- else
- node->AddChildLast(ParseFunction());
- }
- else if( t1.type == ttEndStatement )
- {
- // Ignore a semicolon by itself
- GetToken(&t1);
- }
- else if( t1.type == ttEnd )
- return node;
- else
- {
- asCString str;
- const char *t = asGetTokenDefinition(t1.type);
- if( t == 0 ) t = "<unknown token>";
- str.Format(TXT_UNEXPECTED_TOKEN_s, t);
- Error(str.AddressOf(), &t1);
- }
- }
- if( isSyntaxError )
- {
- // Search for either ';' or '{' or end
- GetToken(&t1);
- while( t1.type != ttEndStatement && t1.type != ttEnd &&
- t1.type != ttStartStatementBlock )
- GetToken(&t1);
- if( t1.type == ttStartStatementBlock )
- {
- // Find the end of the block and skip nested blocks
- int level = 1;
- while( level > 0 )
- {
- GetToken(&t1);
- if( t1.type == ttStartStatementBlock ) level++;
- if( t1.type == ttEndStatementBlock ) level--;
- if( t1.type == ttEnd ) break;
- }
- }
- isSyntaxError = false;
- }
- }
- UNREACHABLE_RETURN;
- }
- int asCParser::ParseStatementBlock(asCScriptCode *script, asCScriptNode *block)
- {
- Reset();
- // Tell the parser to validate the identifiers as valid types
- checkValidTypes = true;
- this->script = script;
- sourcePos = block->tokenPos;
- scriptNode = ParseStatementBlock();
- if( isSyntaxError || errorWhileParsing )
- return -1;
- return 0;
- }
- asCScriptNode *asCParser::ParseEnumeration()
- {
- asCScriptNode *ident;
- asCScriptNode *dataType;
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snEnum);
- sToken token;
- // Check for enum
- GetToken(&token);
- if( token.type != ttEnum )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEnum)).AddressOf(), &token);
- return node;
- }
- node->SetToken(&token);
- node->UpdateSourcePos(token.pos, token.length);
- // Get the identifier
- GetToken(&token);
- if(ttIdentifier != token.type)
- {
- Error(TXT_EXPECTED_IDENTIFIER, &token);
- return node;
- }
- dataType = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
- node->AddChildLast(dataType);
- ident = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snIdentifier);
- ident->SetToken(&token);
- ident->UpdateSourcePos(token.pos, token.length);
- dataType->AddChildLast(ident);
- // check for the start of the declaration block
- GetToken(&token);
- if( token.type != ttStartStatementBlock )
- {
- RewindTo(&token);
- Error(ExpectedToken(asGetTokenDefinition(token.type)).AddressOf(), &token);
- return node;
- }
- while(ttEnd != token.type)
- {
- GetToken(&token);
- if( ttEndStatementBlock == token.type )
- {
- RewindTo(&token);
- break;
- }
- if(ttIdentifier != token.type)
- {
- Error(TXT_EXPECTED_IDENTIFIER, &token);
- return node;
- }
- // Add the enum element
- ident = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snIdentifier);
- ident->SetToken(&token);
- ident->UpdateSourcePos(token.pos, token.length);
- node->AddChildLast(ident);
- GetToken(&token);
- if( token.type == ttAssignment )
- {
- asCScriptNode *tmp;
- RewindTo(&token);
- tmp = SuperficiallyParseGlobalVarInit();
- node->AddChildLast(tmp);
- if( isSyntaxError ) return node;
- GetToken(&token);
- }
- if(ttListSeparator != token.type)
- {
- RewindTo(&token);
- break;
- }
- }
- // check for the end of the declaration block
- GetToken(&token);
- if( token.type != ttEndStatementBlock )
- {
- RewindTo(&token);
- Error(ExpectedToken(asGetTokenDefinition(token.type)).AddressOf(), &token);
- return node;
- }
- // Parse the declarations
- return node;
- }
- bool asCParser::CheckTemplateType(sToken &t)
- {
- // Is this a template type?
- asCString typeName;
- typeName.Assign(&script->code[t.pos], t.length);
- if( engine->IsTemplateType(typeName.AddressOf()) )
- {
- // Expect the sub type within < >
- GetToken(&t);
- if( t.type != ttLessThan )
- return false;
- // Now there must be a data type
- GetToken(&t);
- if( !IsDataType(t) )
- return false;
- if( !CheckTemplateType(t) )
- return false;
- GetToken(&t);
- // Is it a handle or array?
- while( t.type == ttHandle || t.type == ttOpenBracket )
- {
- if( t.type == ttOpenBracket )
- {
- GetToken(&t);
- if( t.type != ttCloseBracket )
- return false;
- }
- GetToken(&t);
- }
- // Accept >> and >>> tokens too. But then force the tokenizer to move
- // only 1 character ahead (thus splitting the token in two).
- if( script->code[t.pos] != '>' )
- return false;
- else if( t.length != 1 )
- {
- // We need to break the token, so that only the first character is parsed
- sToken t2 = t;
- t2.pos = t.pos + 1;
- RewindTo(&t2);
- }
- }
- return true;
- }
- bool asCParser::IsVarDecl()
- {
- // Set start point so that we can rewind
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- // A class property decl can be preceded by 'private'
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttPrivate )
- RewindTo(&t1);
- // A variable decl can start with a const
- GetToken(&t1);
- if( t1.type == ttConst )
- GetToken(&t1);
- // We don't validate if the identifier is an actual declared type at this moment
- // as it may wrongly identify the statement as a non-declaration if the user typed
- // the name incorrectly. The real type is validated in ParseDeclaration where a
- // proper error message can be given.
- if( !IsRealType(t1.type) && t1.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- if( !CheckTemplateType(t1) )
- {
- RewindTo(&t);
- return false;
- }
- // Object handles can be interleaved with the array brackets
- sToken t2;
- GetToken(&t2);
- while( t2.type == ttHandle || t2.type == ttOpenBracket )
- {
- if( t2.type == ttOpenBracket )
- {
- GetToken(&t2);
- if( t2.type != ttCloseBracket )
- {
- RewindTo(&t);
- return false;
- }
- }
- GetToken(&t2);
- }
- if( t2.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- GetToken(&t2);
- if( t2.type == ttEndStatement || t2.type == ttAssignment || t2.type == ttListSeparator )
- {
- RewindTo(&t);
- return true;
- }
- if( t2.type == ttOpenParanthesis )
- {
- // If the closing paranthesis is followed by a statement
- // block or end-of-file, then treat it as a function.
- while( t2.type != ttCloseParanthesis && t2.type != ttEnd )
- GetToken(&t2);
- if( t2.type == ttEnd )
- return false;
- else
- {
- GetToken(&t1);
- RewindTo(&t);
- if( t1.type == ttStartStatementBlock || t1.type == ttEnd )
- return false;
- }
- RewindTo(&t);
- return true;
- }
- RewindTo(&t);
- return false;
- }
- bool asCParser::IsFuncDecl(bool isMethod)
- {
- // Set start point so that we can rewind
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- // A class method decl can be preceded by 'private'
- if( isMethod )
- {
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttPrivate )
- RewindTo(&t1);
- }
- // A class constructor starts with identifier followed by parenthesis
- // A class destructor starts with the ~ token
- if( isMethod )
- {
- sToken t1, t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- if( (t1.type == ttIdentifier && t2.type == ttOpenParanthesis) || t1.type == ttBitNot )
- {
- RewindTo(&t);
- return true;
- }
- }
- // A function decl can start with a const
- sToken t1;
- GetToken(&t1);
- if( t1.type == ttConst )
- GetToken(&t1);
- if( !IsDataType(t1) )
- {
- RewindTo(&t);
- return false;
- }
- if( !CheckTemplateType(t1) )
- {
- RewindTo(&t);
- return false;
- }
- // Object handles can be interleaved with the array brackets
- sToken t2;
- GetToken(&t2);
- while( t2.type == ttHandle || t2.type == ttOpenBracket )
- {
- if( t2.type == ttOpenBracket )
- {
- GetToken(&t2);
- if( t2.type != ttCloseBracket )
- {
- RewindTo(&t);
- return false;
- }
- }
- GetToken(&t2);
- }
- // There can be an ampersand if the function returns a reference
- if( t2.type == ttAmp )
- {
- RewindTo(&t);
- return true;
- }
- if( t2.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- GetToken(&t2);
- if( t2.type == ttOpenParanthesis )
- {
- // If the closing paranthesis is not followed by a
- // statement block then it is not a function.
- while( t2.type != ttCloseParanthesis && t2.type != ttEnd )
- GetToken(&t2);
- if( t2.type == ttEnd )
- return false;
- else
- {
- // A class method can have a 'const' token after the parameter list
- if( isMethod )
- {
- GetToken(&t1);
- if( t1.type != ttConst )
- RewindTo(&t1);
- }
- GetToken(&t1);
- RewindTo(&t);
- if( t1.type == ttStartStatementBlock )
- return true;
- }
- RewindTo(&t);
- return false;
- }
- RewindTo(&t);
- return false;
- }
- asCScriptNode *asCParser::ParseFuncDef()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFuncDef);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttFuncDef )
- {
- Error(asGetTokenDefinition(ttFuncDef), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseParameterList());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttEndStatement )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttEndStatement)).AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseFunction(bool isMethod)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFunction);
- sToken t1,t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- // A class method can start with private
- if( isMethod && t1.type == ttPrivate )
- {
- node->AddChildLast(ParseToken(ttPrivate));
- if( isSyntaxError ) return node;
- }
- // If it is a global function, or a method, except constructor and destructor, then the return type is parsed
- if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) )
- {
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- }
- // If this is a class destructor then it starts with ~, and no return type is declared
- if( isMethod && t1.type == ttBitNot )
- {
- node->AddChildLast(ParseToken(ttBitNot));
- if( isSyntaxError ) return node;
- }
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseParameterList());
- if( isSyntaxError ) return node;
- if( isMethod )
- {
- // Is the method a const?
- GetToken(&t1);
- RewindTo(&t1);
- if( t1.type == ttConst )
- node->AddChildLast(ParseToken(ttConst));
- }
- // We should just find the end of the statement block here. The statements
- // will be parsed on request by the compiler once it starts the compilation.
- node->AddChildLast(SuperficiallyParseStatementBlock());
- return node;
- }
- asCScriptNode *asCParser::ParseInterfaceMethod()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFunction);
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseParameterList());
- if( isSyntaxError ) return node;
- // Parse an optional const after the method definition
- sToken t1;
- GetToken(&t1);
- RewindTo(&t1);
- if( t1.type == ttConst )
- node->AddChildLast(ParseToken(ttConst));
- GetToken(&t1);
- if( t1.type != ttEndStatement )
- {
- Error(ExpectedToken(";").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseInterface()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snInterface);
- sToken t;
- GetToken(&t);
- // Allow keyword 'shared' before 'interface'
- if( t.type == ttIdentifier )
- {
- asCString str;
- str.Assign(&script->code[t.pos], t.length);
- if( str != SHARED_TOKEN )
- {
- Error(ExpectedToken(SHARED_TOKEN).AddressOf(), &t);
- return node;
- }
- RewindTo(&t);
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- if( t.type != ttInterface )
- {
- Error(ExpectedToken("interface").AddressOf(), &t);
- return node;
- }
- node->SetToken(&t);
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t);
- return node;
- }
- // Parse interface methods
- GetToken(&t);
- RewindTo(&t);
- while( t.type != ttEndStatementBlock && t.type != ttEnd )
- {
- // Parse the method signature
- node->AddChildLast(ParseInterfaceMethod());
- if( isSyntaxError ) return node;
-
- GetToken(&t);
- RewindTo(&t);
- }
- GetToken(&t);
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseClass()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snClass);
- sToken t;
- GetToken(&t);
- // Allow the keyword 'shared' before 'class'
- if( t.type == ttIdentifier )
- {
- asCString str;
- str.Assign(&script->code[t.pos], t.length);
- if( str != SHARED_TOKEN )
- {
- Error(ExpectedToken(SHARED_TOKEN).AddressOf(), &t);
- return node;
- }
- RewindTo(&t);
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- if( t.type != ttClass )
- {
- Error(ExpectedToken("class").AddressOf(), &t);
- return node;
- }
- node->SetToken(&t);
- if( engine->ep.allowImplicitHandleTypes )
- {
- // Parse 'implicit handle class' construct
- GetToken(&t);
-
- if ( t.type == ttHandle )
- node->SetToken(&t);
- else
- RewindTo(&t);
- }
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- // Optional list of interfaces that are being implemented and classes that are being inherited
- if( t.type == ttColon )
- {
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- while( t.type == ttListSeparator )
- {
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- }
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t);
- return node;
- }
- // Parse properties
- GetToken(&t);
- RewindTo(&t);
- while( t.type != ttEndStatementBlock && t.type != ttEnd )
- {
- // Is it a property or a method?
- if( IsFuncDecl(true) )
- {
- // Parse the method
- node->AddChildLast(ParseFunction(true));
- }
- else if( IsVarDecl() )
- {
- // Parse a property declaration
- asCScriptNode *prop = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDeclaration);
- node->AddChildLast(prop);
- // A variable declaration can be preceded by 'private'
- if( t.type == ttPrivate )
- prop->AddChildLast(ParseToken(ttPrivate));
- prop->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- prop->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";").AddressOf(), &t);
- return node;
- }
- prop->UpdateSourcePos(t.pos, t.length);
- }
- else
- {
- Error(TXT_EXPECTED_METHOD_OR_PROPERTY, &t);
- return node;
- }
- GetToken(&t);
- RewindTo(&t);
- }
- GetToken(&t);
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseGlobalVar()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snGlobalVar);
- // Parse data type
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- sToken t;
- for(;;)
- {
- // Parse identifier
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- // Only superficially parse the initialization info for the variable
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttAssignment || t.type == ttOpenParanthesis )
- {
- node->AddChildLast(SuperficiallyParseGlobalVarInit());
- if( isSyntaxError ) return node;
- }
- // continue if list separator, else terminate with end statement
- GetToken(&t);
- if( t.type == ttListSeparator )
- continue;
- else if( t.type == ttEndStatement )
- {
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- else
- {
- Error(ExpectedTokens(",", ";").AddressOf(), &t);
- return node;
- }
- }
- UNREACHABLE_RETURN;
- }
- int asCParser::ParseGlobalVarInit(asCScriptCode *script, asCScriptNode *init)
- {
- Reset();
- // Tell the parser to validate the identifiers as valid types
- checkValidTypes = true;
- this->script = script;
- sourcePos = init->tokenPos;
- // If next token is assignment, parse expression
- sToken t;
- GetToken(&t);
- if( t.type == ttAssignment )
- {
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttStartStatementBlock )
- scriptNode = ParseInitList();
- else
- scriptNode = ParseAssignment();
- }
- else if( t.type == ttOpenParanthesis )
- {
- RewindTo(&t);
- scriptNode = ParseArgList();
- }
- else
- {
- int tokens[] = {ttAssignment, ttOpenParanthesis};
- Error(ExpectedOneOf(tokens, 2).AddressOf(), &t);
- }
- if( isSyntaxError || errorWhileParsing )
- return -1;
- return 0;
- }
- asCScriptNode *asCParser::SuperficiallyParseGlobalVarInit()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snAssignment);
- sToken t;
- GetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- if( t.type == ttAssignment )
- {
- GetToken(&t);
- if( t.type == ttStartStatementBlock )
- {
- // Find the end of the initialization list
- int indent = 1;
- while( indent )
- {
- GetToken(&t);
- if( t.type == ttStartStatementBlock )
- indent++;
- else if( t.type == ttEndStatementBlock )
- indent--;
- else if( t.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- break;
- }
- }
- }
- else
- {
- // Find the end of the expression
- int indent = 0;
- while( indent || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
- {
- if( t.type == ttOpenParanthesis )
- indent++;
- else if( t.type == ttCloseParanthesis )
- indent--;
- else if( t.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- break;
- }
- GetToken(&t);
- }
- // Rewind so that the next token read is the list separator, end statement, or end statement block
- RewindTo(&t);
- }
- }
- else if( t.type == ttOpenParanthesis )
- {
- // Find the end of the argument list
- int indent = 1;
- while( indent )
- {
- GetToken(&t);
- if( t.type == ttOpenParanthesis )
- indent++;
- else if( t.type == ttCloseParanthesis )
- indent--;
- else if( t.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- break;
- }
- }
- }
- else
- {
- int tokens[] = {ttAssignment, ttOpenParanthesis};
- Error(ExpectedOneOf(tokens, 2).AddressOf(), &t);
- }
- return node;
- }
- asCScriptNode *asCParser::ParseTypeMod(bool isParam)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
- sToken t;
- // Parse possible & token
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttAmp )
- {
- node->AddChildLast(ParseToken(ttAmp));
- if( isSyntaxError ) return node;
- if( isParam )
- {
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttIn || t.type == ttOut || t.type == ttInOut )
- {
- int tokens[3] = {ttIn, ttOut, ttInOut};
- node->AddChildLast(ParseOneOf(tokens, 3));
- }
- }
- }
- // Parse possible + token
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttPlus )
- {
- node->AddChildLast(ParseToken(ttPlus));
- if( isSyntaxError ) return node;
- }
- return node;
- }
- asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
- sToken t;
- if( allowConst )
- {
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttConst )
- {
- node->AddChildLast(ParseToken(ttConst));
- if( isSyntaxError ) return node;
- }
- }
- node->AddChildLast(ParseDataType(allowVariableType));
- // If the datatype is a template type, then parse the subtype within the < >
- asCScriptNode *type = node->lastChild;
- asCString typeName;
- typeName.Assign(&script->code[type->tokenPos], type->tokenLength);
- if( engine->IsTemplateType(typeName.AddressOf()) )
- {
- GetToken(&t);
- if( t.type != ttLessThan )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttLessThan)).AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseType(true, false));
- if( isSyntaxError ) return node;
- // Accept >> and >>> tokens too. But then force the tokenizer to move
- // only 1 character ahead (thus splitting the token in two).
- GetToken(&t);
- if( script->code[t.pos] != '>' )
- {
- Error(ExpectedToken(asGetTokenDefinition(ttGreaterThan)).AddressOf(), &t);
- return node;
- }
- else
- {
- // Break the token so that only the first > is parsed
- sToken t2 = t;
- t2.pos = t.pos + 1;
- RewindTo(&t2);
- }
- }
- // Parse [] and @
- GetToken(&t);
- RewindTo(&t);
- while( t.type == ttOpenBracket || t.type == ttHandle)
- {
- if( t.type == ttOpenBracket )
- {
- node->AddChildLast(ParseToken(ttOpenBracket));
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseBracket )
- {
- Error(ExpectedToken("]").AddressOf(), &t);
- return node;
- }
- }
- else
- {
- node->AddChildLast(ParseToken(ttHandle));
- if( isSyntaxError ) return node;
- }
- GetToken(&t);
- RewindTo(&t);
- }
- return node;
- }
- asCScriptNode *asCParser::ParseToken(int token)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined);
- sToken t1;
- GetToken(&t1);
- if( t1.type != token )
- {
- Error(ExpectedToken(asGetTokenDefinition(token)).AddressOf(), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseOneOf(int *tokens, int count)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined);
- sToken t1;
- GetToken(&t1);
- int n;
- for( n = 0; n < count; n++ )
- {
- if( tokens[n] == t1.type )
- break;
- }
- if( n == count )
- {
- Error(ExpectedOneOf(tokens, count).AddressOf(), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseDataType(bool allowVariableType)
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
- sToken t1;
- GetToken(&t1);
- if( !IsDataType(t1) && !(allowVariableType && t1.type == ttQuestion) )
- {
- if( t1.type == ttIdentifier )
- {
- asCString errMsg, Identifier;
- Identifier.Assign(&script->code[t1.pos], t1.length);
- errMsg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, Identifier.AddressOf());
- Error(errMsg.AddressOf(), &t1);
- }
- else
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseRealType()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDataType);
- sToken t1;
- GetToken(&t1);
- if( !IsRealType(t1.type) )
- {
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseIdentifier()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snIdentifier);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttIdentifier )
- {
- Error(TXT_EXPECTED_IDENTIFIER, &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseCast()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snCast);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttCast )
- {
- Error(ExpectedToken("cast").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- GetToken(&t1);
- if( t1.type != ttLessThan )
- {
- Error(ExpectedToken("<").AddressOf(), &t1);
- return node;
- }
- // Parse the data type
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttGreaterThan )
- {
- Error(ExpectedToken(">").AddressOf(), &t1);
- return node;
- }
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t1);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseParameterList()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snParameterList);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- GetToken(&t1);
- if( t1.type == ttCloseParanthesis )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- // If the parameter list is just (void) then the void token should be ignored
- if( t1.type == ttVoid )
- {
- sToken t2;
- GetToken(&t2);
- if( t2.type == ttCloseParanthesis )
- {
- node->UpdateSourcePos(t2.pos, t2.length);
- return node;
- }
- }
- RewindTo(&t1);
- for(;;)
- {
- // Parse data type
- node->AddChildLast(ParseType(true, isParsingAppInterface));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(true));
- if( isSyntaxError ) return node;
- // Parse identifier
- GetToken(&t1);
- if( t1.type == ttIdentifier )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- // Parse the expression for the default arg
- if( t1.type == ttAssignment )
- {
- node->AddChildLast(ParseExpression());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- }
- }
- // Check if list continues
- if( t1.type == ttCloseParanthesis )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- else if( t1.type == ttListSeparator )
- continue;
- else
- {
- Error(ExpectedTokens(")", ",").AddressOf(), &t1);
- return node;
- }
- }
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::ParseExprValue()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprValue);
- sToken t1, t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- // TODO: namespace: Datatypes can be defined in namespaces, thus types too must allow scope prefix
- if( IsDataType(t1) && (t2.type == ttOpenParanthesis ||
- t2.type == ttLessThan ||
- t2.type == ttOpenBracket) )
- node->AddChildLast(ParseConstructCall());
- else if( t1.type == ttIdentifier || t1.type == ttScope )
- {
- if( IsFunctionCall() )
- node->AddChildLast(ParseFunctionCall());
- else
- node->AddChildLast(ParseVariableAccess());
- }
- else if( t1.type == ttCast )
- node->AddChildLast(ParseCast());
- else if( IsConstant(t1.type) )
- node->AddChildLast(ParseConstant());
- else if( t1.type == ttOpenParanthesis )
- {
- GetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttCloseParanthesis )
- Error(ExpectedToken(")").AddressOf(), &t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- }
- else
- Error(TXT_EXPECTED_EXPRESSION_VALUE, &t1);
- return node;
- }
- asCScriptNode *asCParser::ParseConstant()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snConstant);
- sToken t;
- GetToken(&t);
- if( !IsConstant(t.type) )
- {
- Error(TXT_EXPECTED_CONSTANT, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- // We want to gather a list of string constants to concatenate as children
- if( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant )
- RewindTo(&t);
- while( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant )
- {
- node->AddChildLast(ParseStringConstant());
- GetToken(&t);
- RewindTo(&t);
- }
- return node;
- }
- asCScriptNode *asCParser::ParseStringConstant()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snConstant);
- sToken t;
- GetToken(&t);
- if( t.type != ttStringConstant && t.type != ttMultilineStringConstant && t.type != ttHeredocStringConstant )
- {
- Error(TXT_EXPECTED_STRING, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseFunctionCall()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFunctionCall);
- // Parse scope prefix
- sToken t1, t2;
- GetToken(&t1);
- if( t1.type == ttScope )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- }
- GetToken(&t2);
- while( t1.type == ttIdentifier && t2.type == ttScope )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- node->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- GetToken(&t2);
- }
- RewindTo(&t1);
- // Parse the function name followed by the argument list
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseArgList());
- return node;
- }
- asCScriptNode *asCParser::ParseVariableAccess()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snVariableAccess);
- // Parse scope prefix
- sToken t1, t2;
- GetToken(&t1);
- if( t1.type == ttScope )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- }
- GetToken(&t2);
- while( t1.type == ttIdentifier && t2.type == ttScope )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- node->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- GetToken(&t2);
- }
- RewindTo(&t1);
- // Parse the variable name
- node->AddChildLast(ParseIdentifier());
- return node;
- }
- asCScriptNode *asCParser::ParseConstructCall()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snConstructCall);
- node->AddChildLast(ParseType(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseArgList());
- return node;
- }
- asCScriptNode *asCParser::ParseArgList()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snArgList);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- GetToken(&t1);
- if( t1.type == ttCloseParanthesis )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- RewindTo(&t1);
- for(;;)
- {
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- // Check if list continues
- GetToken(&t1);
- if( t1.type == ttCloseParanthesis )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- else if( t1.type == ttListSeparator )
- continue;
- else
- {
- Error(ExpectedTokens(")", ",").AddressOf(), &t1);
- return node;
- }
- }
- }
- return 0;
- }
- asCScriptNode *asCParser::SuperficiallyParseStatementBlock()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snStatementBlock);
- // This function will only superficially parse the statement block in order to find the end of it
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- int level = 1;
- while( level > 0 && !isSyntaxError )
- {
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- level--;
- else if( t1.type == ttStartStatementBlock )
- level++;
- else if( t1.type == ttEnd )
- Error(TXT_UNEXPECTED_END_OF_FILE, &t1);
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseStatementBlock()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snStatementBlock);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- for(;;)
- {
- while( !isSyntaxError )
- {
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- RewindTo(&t1);
- if( IsVarDecl() )
- node->AddChildLast(ParseDeclaration());
- else
- node->AddChildLast(ParseStatement());
- }
- }
- if( isSyntaxError )
- {
- // Search for either ';', '{', '}', or end
- GetToken(&t1);
- while( t1.type != ttEndStatement && t1.type != ttEnd &&
- t1.type != ttStartStatementBlock && t1.type != ttEndStatementBlock )
- {
- GetToken(&t1);
- }
- // Skip this statement block
- if( t1.type == ttStartStatementBlock )
- {
- // Find the end of the block and skip nested blocks
- int level = 1;
- while( level > 0 )
- {
- GetToken(&t1);
- if( t1.type == ttStartStatementBlock ) level++;
- if( t1.type == ttEndStatementBlock ) level--;
- if( t1.type == ttEnd ) break;
- }
- }
- else if( t1.type == ttEndStatementBlock )
- {
- RewindTo(&t1);
- }
- else if( t1.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t1);
- return node;
- }
- isSyntaxError = false;
- }
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::ParseInitList()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snInitList);
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- RewindTo(&t1);
- for(;;)
- {
- GetToken(&t1);
- if( t1.type == ttListSeparator )
- {
- // No expression
- node->AddChildLast(new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined));
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- {
- // No expression
- node->AddChildLast(new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined));
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- RewindTo(&t1);
- }
- else if( t1.type == ttEndStatementBlock )
- {
- // No expression
- node->AddChildLast(new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snUndefined));
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else if( t1.type == ttStartStatementBlock )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseInitList());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type == ttListSeparator )
- continue;
- else if( t1.type == ttEndStatementBlock )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- Error(ExpectedTokens("}", ",").AddressOf(), &t1);
- return node;
- }
- }
- else
- {
- RewindTo(&t1);
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type == ttListSeparator )
- continue;
- else if( t1.type == ttEndStatementBlock )
- {
- node->UpdateSourcePos(t1.pos, t1.length);
- // Statement block is finished
- return node;
- }
- else
- {
- Error(ExpectedTokens("}", ",").AddressOf(), &t1);
- return node;
- }
- }
- }
- }
- UNREACHABLE_RETURN;
- }
- bool asCParser::IsFunctionCall()
- {
- sToken s;
- sToken t1, t2;
- GetToken(&s);
- t1 = s;
- // A function call may be prefixed with scope resolution
- if( t1.type == ttScope )
- GetToken(&t1);
- GetToken(&t2);
- while( t1.type == ttIdentifier && t2.type == ttScope )
- {
- GetToken(&t1);
- GetToken(&t2);
- }
- // A function call starts with an identifier followed by an argument list
- if( t1.type != ttIdentifier || IsDataType(t1) )
- {
- RewindTo(&s);
- return false;
- }
- if( t2.type == ttOpenParanthesis )
- {
- RewindTo(&s);
- return true;
- }
- RewindTo(&s);
- return false;
- }
- asCScriptNode *asCParser::ParseDeclaration()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDeclaration);
- // Parse data type
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- sToken t;
- for(;;)
- {
- // Parse identifier
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- // If next token is assignment, parse expression
- GetToken(&t);
- if( t.type == ttOpenParanthesis )
- {
- RewindTo(&t);
- node->AddChildLast(ParseArgList());
- if( isSyntaxError ) return node;
- }
- else if( t.type == ttAssignment )
- {
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttStartStatementBlock )
- {
- node->AddChildLast(ParseInitList());
- if( isSyntaxError ) return node;
- }
- else
- {
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- }
- }
- else
- RewindTo(&t);
- // continue if list separator, else terminate with end statement
- GetToken(&t);
- if( t.type == ttListSeparator )
- continue;
- else if( t.type == ttEndStatement )
- {
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- else
- {
- Error(ExpectedTokens(",", ";").AddressOf(), &t);
- return node;
- }
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::ParseStatement()
- {
- sToken t1;
- GetToken(&t1);
- RewindTo(&t1);
- if( t1.type == ttIf )
- return ParseIf();
- else if( t1.type == ttFor )
- return ParseFor();
- else if( t1.type == ttWhile )
- return ParseWhile();
- else if( t1.type == ttReturn )
- return ParseReturn();
- else if( t1.type == ttStartStatementBlock )
- return ParseStatementBlock();
- else if( t1.type == ttBreak )
- return ParseBreak();
- else if( t1.type == ttContinue )
- return ParseContinue();
- else if( t1.type == ttDo )
- return ParseDoWhile();
- else if( t1.type == ttSwitch )
- return ParseSwitch();
- else
- return ParseExpressionStatement();
- }
- asCScriptNode *asCParser::ParseExpressionStatement()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExpressionStatement);
- sToken t;
- GetToken(&t);
- if( t.type == ttEndStatement )
- {
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- RewindTo(&t);
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseSwitch()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snSwitch);
- sToken t;
- GetToken(&t);
- if( t.type != ttSwitch )
- {
- Error(ExpectedToken("switch").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{").AddressOf(), &t);
- return node;
- }
-
- while( !isSyntaxError )
- {
- GetToken(&t);
-
- if( t.type == ttEndStatementBlock || t.type == ttDefault)
- break;
- RewindTo(&t);
- if( t.type != ttCase )
- {
- Error(ExpectedToken("case").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseCase());
- if( isSyntaxError ) return node;
- }
- if( t.type == ttDefault)
- {
- RewindTo(&t);
- node->AddChildLast(ParseCase());
- if( isSyntaxError ) return node;
- GetToken(&t);
- }
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}").AddressOf(), &t);
- return node;
- }
- return node;
- }
- asCScriptNode *asCParser::ParseCase()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snCase);
- sToken t;
- GetToken(&t);
- if( t.type != ttCase && t.type != ttDefault )
- {
- Error(ExpectedTokens("case", "default").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- if(t.type == ttCase)
- {
- node->AddChildLast(ParseExpression());
- }
- GetToken(&t);
- if( t.type != ttColon )
- {
- Error(ExpectedToken(":").AddressOf(), &t);
- return node;
- }
- // Parse statements until we find either of }, case, default, and break
- GetToken(&t);
- RewindTo(&t);
- while( t.type != ttCase &&
- t.type != ttDefault &&
- t.type != ttEndStatementBlock &&
- t.type != ttBreak )
- {
- if( IsVarDecl() )
- // Variable declarations are not allowed, but we parse it anyway to give a good error message
- node->AddChildLast(ParseDeclaration());
- else
- node->AddChildLast(ParseStatement());
- if( isSyntaxError ) return node;
- GetToken(&t);
- RewindTo(&t);
- }
- // If the case was ended with a break statement, add it to the node
- if( t.type == ttBreak )
- node->AddChildLast(ParseBreak());
- return node;
- }
- asCScriptNode *asCParser::ParseIf()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snIf);
- sToken t;
- GetToken(&t);
- if( t.type != ttIf )
- {
- Error(ExpectedToken("if").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseStatement());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttElse )
- {
- // No else statement return already
- RewindTo(&t);
- return node;
- }
- node->AddChildLast(ParseStatement());
- return node;
- }
- asCScriptNode *asCParser::ParseFor()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snFor);
- sToken t;
- GetToken(&t);
- if( t.type != ttFor )
- {
- Error(ExpectedToken("for").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t);
- return node;
- }
- if( IsVarDecl() )
- node->AddChildLast(ParseDeclaration());
- else
- node->AddChildLast(ParseExpressionStatement());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseExpressionStatement());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- RewindTo(&t);
- asCScriptNode *n = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExpressionStatement);
- node->AddChildLast(n);
- n->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t);
- return node;
- }
- }
- node->AddChildLast(ParseStatement());
-
- return node;
- }
-
- asCScriptNode *asCParser::ParseWhile()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snWhile);
- sToken t;
- GetToken(&t);
- if( t.type != ttWhile )
- {
- Error(ExpectedToken("while").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseStatement());
- return node;
- }
- asCScriptNode *asCParser::ParseDoWhile()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snDoWhile);
- sToken t;
- GetToken(&t);
- if( t.type != ttDo )
- {
- Error(ExpectedToken("do").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- node->AddChildLast(ParseStatement());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttWhile )
- {
- Error(ExpectedToken("while").AddressOf(), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("(").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")").AddressOf(), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseReturn()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snReturn);
- sToken t;
- GetToken(&t);
- if( t.type != ttReturn )
- {
- Error(ExpectedToken("return").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type == ttEndStatement )
- {
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- RewindTo(&t);
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseBreak()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snBreak);
- sToken t;
- GetToken(&t);
- if( t.type != ttBreak )
- {
- Error(ExpectedToken("break").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- Error(ExpectedToken(";").AddressOf(), &t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseContinue()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snContinue);
- sToken t;
- GetToken(&t);
- if( t.type != ttContinue )
- {
- Error(ExpectedToken("continue").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- Error(ExpectedToken(";").AddressOf(), &t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseAssignment()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snAssignment);
- node->AddChildLast(ParseCondition());
- if( isSyntaxError ) return node;
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- if( IsAssignOperator(t.type) )
- {
- node->AddChildLast(ParseAssignOperator());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- }
- return node;
- }
- asCScriptNode *asCParser::ParseCondition()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snCondition);
- node->AddChildLast(ParseExpression());
- if( isSyntaxError ) return node;
- sToken t;
- GetToken(&t);
- if( t.type == ttQuestion )
- {
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttColon )
- {
- Error(ExpectedToken(":").AddressOf(), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- }
- else
- RewindTo(&t);
- return node;
- }
- asCScriptNode *asCParser::ParseExpression()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExpression);
- node->AddChildLast(ParseExprTerm());
- if( isSyntaxError ) return node;
- for(;;)
- {
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- if( !IsOperator(t.type) )
- return node;
- node->AddChildLast(ParseExprOperator());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseExprTerm());
- if( isSyntaxError ) return node;
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::ParseExprTerm()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprTerm);
- for(;;)
- {
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- if( !IsPreOperator(t.type) )
- break;
- node->AddChildLast(ParseExprPreOp());
- if( isSyntaxError ) return node;
- }
- node->AddChildLast(ParseExprValue());
- if( isSyntaxError ) return node;
-
- for(;;)
- {
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- if( !IsPostOperator(t.type) )
- return node;
- node->AddChildLast(ParseExprPostOp());
- if( isSyntaxError ) return node;
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::ParseExprPreOp()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprPreOp);
- sToken t;
- GetToken(&t);
- if( !IsPreOperator(t.type) )
- {
- Error(TXT_EXPECTED_PRE_OPERATOR, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseExprPostOp()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprPostOp);
- sToken t;
- GetToken(&t);
- if( !IsPostOperator(t.type) )
- {
- Error(TXT_EXPECTED_POST_OPERATOR, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- if( t.type == ttDot )
- {
- sToken t1, t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- if( t2.type == ttOpenParanthesis )
- node->AddChildLast(ParseFunctionCall());
- else
- node->AddChildLast(ParseIdentifier());
- }
- else if( t.type == ttOpenBracket )
- {
- node->AddChildLast(ParseAssignment());
- GetToken(&t);
- if( t.type != ttCloseBracket )
- {
- Error(ExpectedToken("]").AddressOf(), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- }
- return node;
- }
- asCScriptNode *asCParser::ParseExprOperator()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprOperator);
- sToken t;
- GetToken(&t);
- if( !IsOperator(t.type) )
- {
- Error(TXT_EXPECTED_OPERATOR, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- asCScriptNode *asCParser::ParseAssignOperator()
- {
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snExprOperator);
- sToken t;
- GetToken(&t);
- if( !IsAssignOperator(t.type) )
- {
- Error(TXT_EXPECTED_OPERATOR, &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- void asCParser::GetToken(sToken *token)
- {
- size_t sourceLength = script->codeLength;
- do
- {
- if( sourcePos >= sourceLength )
- {
- token->type = ttEnd;
- token->length = 0;
- }
- else
- token->type = tokenizer.GetToken(&script->code[sourcePos], sourceLength - sourcePos, &token->length);
- token->pos = sourcePos;
- // Update state
- sourcePos += token->length;
- }
- // Filter out whitespace and comments
- while( token->type == ttWhiteSpace ||
- token->type == ttOnelineComment ||
- token->type == ttMultilineComment );
- }
- void asCParser::RewindTo(const sToken *token)
- {
- sourcePos = token->pos;
- }
- void asCParser::Error(const char *text, sToken *token)
- {
- RewindTo(token);
- isSyntaxError = true;
- errorWhileParsing = true;
- int row, col;
- script->ConvertPosToRowCol(token->pos, &row, &col);
- if( builder )
- builder->WriteError(script->name.AddressOf(), text, row, col);
- }
- bool asCParser::IsRealType(int tokenType)
- {
- if( tokenType == ttVoid ||
- tokenType == ttInt ||
- tokenType == ttInt8 ||
- tokenType == ttInt16 ||
- tokenType == ttInt64 ||
- tokenType == ttUInt ||
- tokenType == ttUInt8 ||
- tokenType == ttUInt16 ||
- tokenType == ttUInt64 ||
- tokenType == ttFloat ||
- tokenType == ttBool ||
- tokenType == ttDouble )
- return true;
- return false;
- }
- bool asCParser::IsDataType(const sToken &token)
- {
- if( token.type == ttIdentifier )
- {
- if( checkValidTypes )
- {
- // Check if this is a registered type
- asCString str;
- str.Assign(&script->code[token.pos], token.length);
- if( !builder->GetObjectType(str.AddressOf()) && !builder->GetFuncDef(str.AddressOf()) )
- return false;
- }
- return true;
- }
- if( IsRealType(token.type) )
- return true;
- return false;
- }
- bool asCParser::IsOperator(int tokenType)
- {
- if( tokenType == ttPlus ||
- tokenType == ttMinus ||
- tokenType == ttStar ||
- tokenType == ttSlash ||
- tokenType == ttPercent ||
- tokenType == ttAnd ||
- tokenType == ttOr ||
- tokenType == ttXor ||
- tokenType == ttEqual ||
- tokenType == ttNotEqual ||
- tokenType == ttLessThan ||
- tokenType == ttLessThanOrEqual ||
- tokenType == ttGreaterThan ||
- tokenType == ttGreaterThanOrEqual ||
- tokenType == ttAmp ||
- tokenType == ttBitOr ||
- tokenType == ttBitXor ||
- tokenType == ttBitShiftLeft ||
- tokenType == ttBitShiftRight ||
- tokenType == ttBitShiftRightArith ||
- tokenType == ttIs ||
- tokenType == ttNotIs )
- return true;
- return false;
- }
- bool asCParser::IsAssignOperator(int tokenType)
- {
- if( tokenType == ttAssignment ||
- tokenType == ttAddAssign ||
- tokenType == ttSubAssign ||
- tokenType == ttMulAssign ||
- tokenType == ttDivAssign ||
- tokenType == ttModAssign ||
- tokenType == ttAndAssign ||
- tokenType == ttOrAssign ||
- tokenType == ttXorAssign ||
- tokenType == ttShiftLeftAssign ||
- tokenType == ttShiftRightLAssign ||
- tokenType == ttShiftRightAAssign )
- return true;
- return false;
- }
- bool asCParser::IsPreOperator(int tokenType)
- {
- if( tokenType == ttMinus ||
- tokenType == ttPlus ||
- tokenType == ttNot ||
- tokenType == ttInc ||
- tokenType == ttDec ||
- tokenType == ttBitNot ||
- tokenType == ttHandle )
- return true;
- return false;
- }
- bool asCParser::IsPostOperator(int tokenType)
- {
- if( tokenType == ttInc ||
- tokenType == ttDec ||
- tokenType == ttDot ||
- tokenType == ttOpenBracket )
- return true;
- return false;
- }
- bool asCParser::IsConstant(int tokenType)
- {
- if( tokenType == ttIntConstant ||
- tokenType == ttFloatConstant ||
- tokenType == ttDoubleConstant ||
- tokenType == ttStringConstant ||
- tokenType == ttMultilineStringConstant ||
- tokenType == ttHeredocStringConstant ||
- tokenType == ttTrue ||
- tokenType == ttFalse ||
- tokenType == ttBitsConstant ||
- tokenType == ttNull )
- return true;
- return false;
- }
- asCString asCParser::ExpectedToken(const char *token)
- {
- asCString str;
- str.Format(TXT_EXPECTED_s, token);
- return str;
- }
- asCString asCParser::ExpectedTokens(const char *t1, const char *t2)
- {
- asCString str;
- str.Format(TXT_EXPECTED_s_OR_s, t1, t2);
- return str;
- }
- asCString asCParser::ExpectedOneOf(int *tokens, int count)
- {
- asCString str;
- str = TXT_EXPECTED_ONE_OF;
- for( int n = 0; n < count; n++ )
- {
- str += asGetTokenDefinition(tokens[n]);
- if( n < count-1 )
- str += ", ";
- }
- return str;
- }
- // TODO: typedef: Typedefs should accept complex types as well
- asCScriptNode *asCParser::ParseTypedef()
- {
- // Create the typedef node
- asCScriptNode *node = new(engine->memoryMgr.AllocScriptNode()) asCScriptNode(snTypedef);
- sToken token;
- GetToken(&token);
- if( token.type != ttTypedef)
- {
- Error(ExpectedToken(asGetTokenDefinition(token.type)).AddressOf(), &token);
- return node;
- }
-
- node->SetToken(&token);
- node->UpdateSourcePos(token.pos, token.length);
- // Parse the base type
- GetToken(&token);
- RewindTo(&token);
- // Make sure it is a primitive type (except ttVoid)
- if( !IsRealType(token.type) || token.type == ttVoid )
- {
- asCString str;
- str.Format(TXT_UNEXPECTED_TOKEN_s, asGetTokenDefinition(token.type));
- Error(str.AddressOf(), &token);
- return node;
- }
- node->AddChildLast(ParseRealType());
- node->AddChildLast(ParseIdentifier());
- // Check for the end of the typedef
- GetToken(&token);
- if( token.type != ttEndStatement )
- {
- RewindTo(&token);
- Error(ExpectedToken(asGetTokenDefinition(token.type)).AddressOf(), &token);
- }
- return node;
- }
- END_AS_NAMESPACE
|