| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2021 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
- //
- //
- // I've documented the syntax in Extended BNF. You'll find it by doing a search in
- // this file by "BNF:". The starting point for the script language is SCRIPT ::=.
- //
- // Ref: http://matt.might.net/articles/grammars-bnf-ebnf/
- //
- // ( ) - used for grouping
- // { } - 0 or more repetitions
- // [ ] - optional
- // | - or
- // ' ' - token
- //
- #include "as_config.h"
- #include "as_parser.h"
- #include "as_tokendef.h"
- #include "as_texts.h"
- #include "as_debug.h"
- #ifdef _MSC_VER
- #pragma warning(disable:4702) // unreachable code
- #endif
- BEGIN_AS_NAMESPACE
- asCParser::asCParser(asCBuilder *builder)
- {
- 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;
- lastToken.pos = size_t(-1);
- }
- asCScriptNode *asCParser::GetScriptNode()
- {
- return scriptNode;
- }
- int asCParser::ParseFunctionDefinition(asCScriptCode *in_script, bool in_expectListPattern)
- {
- Reset();
- // Set flag that permits ? as datatype for parameters
- isParsingAppInterface = true;
- this->script = in_script;
- scriptNode = ParseFunctionDefinition();
- if( in_expectListPattern )
- scriptNode->AddChildLast(ParseListPattern());
- // The declaration should end after the definition
- if( !isSyntaxError )
- {
- sToken t;
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- asCScriptNode *asCParser::CreateNode(eScriptNode type)
- {
- void *ptr = engine->memoryMgr.AllocScriptNode();
- if( ptr == 0 )
- {
- // Out of memory
- errorWhileParsing = true;
- return 0;
- }
- return new(ptr) asCScriptNode(type);
- }
- int asCParser::ParseDataType(asCScriptCode *in_script, bool in_isReturnType)
- {
- Reset();
- this->script = in_script;
- scriptNode = CreateNode(snDataType);
- if( scriptNode == 0 ) return -1;
- scriptNode->AddChildLast(ParseType(true));
- if( isSyntaxError ) return -1;
- if( in_isReturnType )
- {
- scriptNode->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return -1;
- }
- // The declaration should end after the type
- sToken t;
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- // Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>'
- int asCParser::ParseTemplateDecl(asCScriptCode *in_script)
- {
- Reset();
- this->script = in_script;
- scriptNode = CreateNode(snUndefined);
- if( scriptNode == 0 ) return -1;
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- sToken t;
- GetToken(&t);
- if( t.type != ttLessThan )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- // The class token is optional
- GetToken(&t);
- if( t.type != ttClass )
- RewindTo(&t);
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- // There can be multiple sub types
- GetToken(&t);
- // Parse template types by list separator
- while(t.type == ttListSeparator)
- {
- GetToken(&t);
- if( t.type != ttClass )
- RewindTo(&t);
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- GetToken(&t);
- }
- if( t.type != ttGreaterThan )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- int asCParser::ParsePropertyDeclaration(asCScriptCode *in_script)
- {
- Reset();
- this->script = in_script;
- scriptNode = CreateNode(snDeclaration);
- if( scriptNode == 0 ) return -1;
- scriptNode->AddChildLast(ParseType(true));
- if( isSyntaxError ) return -1;
- // Allow optional '&' to indicate that the property is indirect, i.e. stored as reference
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttAmp )
- scriptNode->AddChildLast(ParseToken(ttAmp));
- // Allow optional namespace to be defined before the identifier in case
- // the declaration is to be used for searching for an existing property
- ParseOptionalScope(scriptNode);
- scriptNode->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return -1;
- // The declaration should end after the identifier
- GetToken(&t);
- if( t.type != ttEnd )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t);
- Error(InsteadFound(t), &t);
- return -1;
- }
- return 0;
- }
- // BNF:5: SCOPE ::= ['::'] {IDENTIFIER '::'} [IDENTIFIER ['<' TYPE {',' TYPE} '>'] '::']
- void asCParser::ParseOptionalScope(asCScriptNode *node)
- {
- asCScriptNode *scope = CreateNode(snScope);
- sToken t1, t2;
- GetToken(&t1);
- GetToken(&t2);
- if( t1.type == ttScope )
- {
- RewindTo(&t1);
- scope->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- GetToken(&t2);
- }
- while( t1.type == ttIdentifier && t2.type == ttScope )
- {
- RewindTo(&t1);
- scope->AddChildLast(ParseIdentifier());
- scope->AddChildLast(ParseToken(ttScope));
- GetToken(&t1);
- GetToken(&t2);
- }
- // The innermost scope may be a template type
- if( t1.type == ttIdentifier && t2.type == ttLessThan )
- {
- tempString.Assign(&script->code[t1.pos], t1.length);
- if (engine->IsTemplateType(tempString.AddressOf()))
- {
- RewindTo(&t1);
- asCScriptNode *restore = scope->lastChild;
- scope->AddChildLast(ParseIdentifier());
- if (ParseTemplTypeList(scope, false))
- {
- GetToken(&t2);
- if (t2.type == ttScope)
- {
- // Template type is part of the scope
- // Nothing more needs to be done
- node->AddChildLast(scope);
- return;
- }
- else
- {
- // The template type is not part of the scope
- // Rewind to the template type and end the scope
- RewindTo(&t1);
- // Restore the previously parsed node
- while (scope->lastChild != restore)
- {
- asCScriptNode *last = scope->lastChild;
- last->DisconnectParent();
- last->Destroy(engine);
- }
- if( scope->lastChild )
- node->AddChildLast(scope);
- else
- scope->Destroy(engine);
- return;
- }
- }
- }
- }
- // The identifier is not part of the scope
- RewindTo(&t1);
- if (scope->lastChild)
- node->AddChildLast(scope);
- else
- scope->Destroy(engine);
- }
- asCScriptNode *asCParser::ParseFunctionDefinition()
- {
- asCScriptNode *node = CreateNode(snFunction);
- if( node == 0 ) return 0;
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- ParseOptionalScope(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));
- // Parse optional attributes
- ParseMethodAttributes(node);
- return node;
- }
- // BNF:4: TYPEMOD ::= ['&' ['in' | 'out' | 'inout']]
- asCScriptNode *asCParser::ParseTypeMod(bool isParam)
- {
- asCScriptNode *node = CreateNode(snDataType);
- if( node == 0 ) return 0;
- 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;
- }
- // Parse possible if_handle_then_const token
- GetToken(&t);
- RewindTo(&t);
- if (IdentifierIs(t, IF_HANDLE_TOKEN))
- {
- node->AddChildLast(ParseToken(ttIdentifier));
- if (isSyntaxError) return node;
- }
- return node;
- }
- // BNF:4: TYPE ::= ['const'] SCOPE DATATYPE ['<' TYPE {',' TYPE} '>'] { ('[' ']') | ('@' ['const']) }
- asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, bool allowAuto)
- {
- asCScriptNode *node = CreateNode(snDataType);
- if( node == 0 ) return 0;
- sToken t;
- if( allowConst )
- {
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttConst )
- {
- node->AddChildLast(ParseToken(ttConst));
- if( isSyntaxError ) return node;
- }
- }
- // Parse scope prefix
- ParseOptionalScope(node);
- // Parse the actual type
- node->AddChildLast(ParseDataType(allowVariableType, allowAuto));
- if( isSyntaxError ) return node;
- // If the datatype is a template type, then parse the subtype within the < >
- GetToken(&t);
- RewindTo(&t);
- asCScriptNode *type = node->lastChild;
- tempString.Assign(&script->code[type->tokenPos], type->tokenLength);
- if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan )
- {
- ParseTemplTypeList(node);
- if (isSyntaxError) return node;
- }
- // 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("]"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- }
- else
- {
- node->AddChildLast(ParseToken(ttHandle));
- if( isSyntaxError ) return node;
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttConst )
- {
- node->AddChildLast(ParseToken(ttConst));
- if( isSyntaxError ) return node;
- }
- }
- GetToken(&t);
- RewindTo(&t);
- }
- return node;
- }
- // This parses a template type list, e.g. <type, type, type>
- // If 'required' is false, and the template type list is not valid,
- // then no change will be done and the function returns false. This
- // can be used as do an optional parsing
- bool asCParser::ParseTemplTypeList(asCScriptNode *node, bool required)
- {
- sToken t;
- bool isValid = true;
- // Remember the last child, so we can restore the state if needed
- asCScriptNode *last = node->lastChild;
- // Starts with '<'
- GetToken(&t);
- if (t.type != ttLessThan)
- {
- if (required)
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t);
- Error(InsteadFound(t), &t);
- }
- return false;
- }
- // At least one type
- // TODO: child funcdef: Make this work with !required
- node->AddChildLast(ParseType(true, false));
- if (isSyntaxError) return false;
- GetToken(&t);
- // Parse template types by list separator
- while (t.type == ttListSeparator)
- {
- // TODO: child funcdef: Make this work with !required
- node->AddChildLast(ParseType(true, false));
- if (isSyntaxError) return false;
- GetToken(&t);
- }
- // End with '>'
- // 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] != '>')
- {
- if (required)
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t);
- Error(InsteadFound(t), &t);
- }
- else
- isValid = false;
- }
- else
- {
- // Break the token so that only the first > is parsed
- SetPos(t.pos + 1);
- }
- if (!required && !isValid)
- {
- // Restore the original state before returning
- while (node->lastChild != last)
- {
- asCScriptNode *n = node->lastChild;
- n->DisconnectParent();
- n->Destroy(engine);
- }
- return false;
- }
- // The template type list was parsed OK
- return true;
- }
- asCScriptNode *asCParser::ParseToken(int token)
- {
- asCScriptNode *node = CreateNode(snUndefined);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != token )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(token)), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- asCScriptNode *asCParser::ParseOneOf(int *tokens, int count)
- {
- asCScriptNode *node = CreateNode(snUndefined);
- if( node == 0 ) return 0;
- 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), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:5: DATATYPE ::= (IDENTIFIER | PRIMTYPE | '?' | 'auto')
- asCScriptNode *asCParser::ParseDataType(bool allowVariableType, bool allowAuto)
- {
- asCScriptNode *node = CreateNode(snDataType);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( !IsDataType(t1) && !(allowVariableType && t1.type == ttQuestion) && !(allowAuto && t1.type == ttAuto) )
- {
- if( t1.type == ttIdentifier )
- {
- asCString errMsg;
- tempString.Assign(&script->code[t1.pos], t1.length);
- errMsg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, tempString.AddressOf());
- Error(errMsg, &t1);
- }
- else if( t1.type == ttAuto )
- {
- Error(TXT_AUTO_NOT_ALLOWED, &t1);
- }
- else
- {
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- Error(InsteadFound(t1), &t1);
- }
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:6: PRIMTYPE ::= 'void' | 'int' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint' | 'uint8' | 'uint16' | 'uint32' | 'uint64' | 'float' | 'double' | 'bool'
- asCScriptNode *asCParser::ParseRealType()
- {
- asCScriptNode *node = CreateNode(snDataType);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( !IsRealType(t1.type) )
- {
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:17: IDENTIFIER ::= single token: starts with letter or _, can include any letter and digit, same as in C++
- asCScriptNode *asCParser::ParseIdentifier()
- {
- asCScriptNode *node = CreateNode(snIdentifier);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttIdentifier )
- {
- Error(TXT_EXPECTED_IDENTIFIER, &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->SetToken(&t1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:3: PARAMLIST ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')'
- asCScriptNode *asCParser::ParseParameterList()
- {
- asCScriptNode *node = CreateNode(snParameterList);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t1);
- Error(InsteadFound(t1), &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 optional identifier
- GetToken(&t1);
- if( t1.type == ttIdentifier )
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- }
- // Parse optional expression for the default arg
- if( t1.type == ttAssignment )
- {
- // Do a superficial parsing of the default argument
- // The actual parsing will be done when the argument is compiled for a function call
- node->AddChildLast(SuperficiallyParseExpression());
- 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(")", ","), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- }
- }
- UNREACHABLE_RETURN;
- }
- asCScriptNode *asCParser::SuperficiallyParseExpression()
- {
- asCScriptNode *node = CreateNode(snExpression);
- if( node == 0 ) return 0;
- // Simply parse everything until the first , or ), whichever comes first.
- // Keeping in mind that () and {} can group expressions.
- sToken start;
- GetToken(&start);
- RewindTo(&start);
- asCString stack;
- sToken t;
- for(;;)
- {
- GetToken(&t);
- if( t.type == ttOpenParanthesis )
- stack += "(";
- else if( t.type == ttCloseParanthesis )
- {
- if( stack == "" )
- {
- // Expression has ended. This token is not part of expression
- RewindTo(&t);
- break;
- }
- else if( stack[stack.GetLength()-1] == '(' )
- {
- // Group has ended
- stack.SetLength(stack.GetLength()-1);
- }
- else
- {
- // Wrong syntax
- RewindTo(&t);
- asCString str;
- str.Format(TXT_UNEXPECTED_TOKEN_s, ")");
- Error(str, &t);
- return node;
- }
- }
- else if( t.type == ttListSeparator )
- {
- if( stack == "" )
- {
- // Expression has ended. This token is not part of expression
- RewindTo(&t);
- break;
- }
- }
- else if( t.type == ttStartStatementBlock )
- stack += "{";
- else if( t.type == ttEndStatementBlock )
- {
- if( stack == "" || stack[stack.GetLength()-1] != '{' )
- {
- // Wrong syntax
- RewindTo(&t);
- asCString str;
- str.Format(TXT_UNEXPECTED_TOKEN_s, "}");
- Error(str, &t);
- return node;
- }
- else
- {
- // Group has ended
- stack.SetLength(stack.GetLength()-1);
- }
- }
- else if( t.type == ttEndStatement )
- {
- // Wrong syntax (since we're parsing a default arg expression)
- RewindTo(&t);
- asCString str;
- str.Format(TXT_UNEXPECTED_TOKEN_s, ";");
- Error(str, &t);
- return node;
- }
- else if( t.type == ttNonTerminatedStringConstant )
- {
- RewindTo(&t);
- Error(TXT_NONTERMINATED_STRING, &t);
- return node;
- }
- else if( t.type == ttEnd )
- {
- // Wrong syntax
- RewindTo(&t);
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- Info(TXT_WHILE_PARSING_EXPRESSION, &start);
- return node;
- }
- // Include the token in the node
- node->UpdateSourcePos(t.pos, t.length);
- }
- return node;
- }
- void asCParser::GetToken(sToken *token)
- {
- // Check if the token has already been parsed
- if( lastToken.pos == sourcePos )
- {
- *token = lastToken;
- sourcePos += token->length;
- if( token->type == ttWhiteSpace ||
- token->type == ttOnelineComment ||
- token->type == ttMultilineComment )
- GetToken(token);
- return;
- }
- // Parse new token
- size_t sourceLength = script->codeLength;
- do
- {
- if( sourcePos >= sourceLength )
- {
- token->type = ttEnd;
- token->length = 0;
- }
- else
- token->type = engine->tok.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::SetPos(size_t pos)
- {
- lastToken.pos = size_t(-1);
- sourcePos = pos;
- }
- void asCParser::RewindTo(const sToken *token)
- {
- // TODO: optimize: Perhaps we can optimize this further by having the parser
- // set an explicit return point, after which each token will
- // be stored. That way not just one token will be reused but
- // no token will have to be tokenized more than once.
- // Store the token so it doesn't have to be tokenized again
- lastToken = *token;
- sourcePos = token->pos;
- }
- void asCParser::Error(const asCString &text, sToken *token)
- {
- RewindTo(token);
- isSyntaxError = true;
- errorWhileParsing = true;
- int row, col;
- script->ConvertPosToRowCol(token->pos, &row, &col);
- if( builder )
- builder->WriteError(script->name, text, row, col);
- }
- void asCParser::Warning(const asCString &text, sToken *token)
- {
- int row, col;
- script->ConvertPosToRowCol(token->pos, &row, &col);
- if( builder )
- builder->WriteWarning(script->name, text, row, col);
- }
- void asCParser::Info(const asCString &text, sToken *token)
- {
- RewindTo(token);
- isSyntaxError = true;
- errorWhileParsing = true;
- int row, col;
- script->ConvertPosToRowCol(token->pos, &row, &col);
- if( builder )
- builder->WriteInfo(script->name, text, row, col, false);
- }
- 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 )
- {
- #ifndef AS_NO_COMPILER
- if( checkValidTypes )
- {
- // Check if this is an existing type, regardless of namespace
- tempString.Assign(&script->code[token.pos], token.length);
- if( !builder->DoesTypeExist(tempString.AddressOf()) )
- return false;
- }
- #endif
- return true;
- }
- if( IsRealType(token.type) )
- 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 += asCTokenizer::GetDefinition(tokens[n]);
- if( n < count-1 )
- str += ", ";
- }
- return str;
- }
- asCString asCParser::ExpectedOneOf(const char **tokens, int count)
- {
- asCString str;
- str = TXT_EXPECTED_ONE_OF;
- for( int n = 0; n < count; n++ )
- {
- str += tokens[n];
- if( n < count-1 )
- str += ", ";
- }
- return str;
- }
- asCString asCParser::InsteadFound(sToken &t)
- {
- asCString str;
- if( t.type == ttIdentifier )
- {
- asCString id(&script->code[t.pos], t.length);
- str.Format(TXT_INSTEAD_FOUND_IDENTIFIER_s, id.AddressOf());
- }
- else if( t.type >= ttIf )
- str.Format(TXT_INSTEAD_FOUND_KEYWORD_s, asCTokenizer::GetDefinition(t.type));
- else
- str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type));
- return str;
- }
- asCScriptNode *asCParser::ParseListPattern()
- {
- asCScriptNode *node = CreateNode(snListPattern);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- sToken start = t1;
- bool isBeginning = true;
- bool afterType = false;
- while( !isSyntaxError )
- {
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- {
- if( !afterType )
- {
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- Error(InsteadFound(t1), &t1);
- }
- break;
- }
- else if( t1.type == ttStartStatementBlock )
- {
- if( afterType )
- {
- Error(ExpectedTokens(",","}"), &t1);
- Error(InsteadFound(t1), &t1);
- }
- RewindTo(&t1);
- node->AddChildLast(ParseListPattern());
- afterType = true;
- }
- else if( t1.type == ttIdentifier && (IdentifierIs(t1, "repeat") || IdentifierIs(t1, "repeat_same")) )
- {
- if( !isBeginning )
- {
- asCString msg;
- asCString token(&script->code[t1.pos], t1.length);
- msg.Format(TXT_UNEXPECTED_TOKEN_s, token.AddressOf());
- Error(msg.AddressOf(), &t1);
- }
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- }
- else if( t1.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t1);
- Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start);
- break;
- }
- else if( t1.type == ttListSeparator )
- {
- if( !afterType )
- {
- Error(TXT_EXPECTED_DATA_TYPE, &t1);
- Error(InsteadFound(t1), &t1);
- }
- afterType = false;
- }
- else
- {
- if( afterType )
- {
- Error(ExpectedTokens(",", "}"), &t1);
- Error(InsteadFound(t1), &t1);
- }
- RewindTo(&t1);
- node->AddChildLast(ParseType(true, true));
- afterType = true;
- }
- isBeginning = false;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- bool asCParser::IdentifierIs(const sToken &t, const char *str)
- {
- if( t.type != ttIdentifier )
- return false;
- return script->TokenEquals(t.pos, t.length, str);
- }
- // BNF:6: FUNCATTR ::= {'override' | 'final' | 'explicit' | 'property'}
- void asCParser::ParseMethodAttributes(asCScriptNode *funcNode)
- {
- sToken t1;
- for(;;)
- {
- GetToken(&t1);
- RewindTo(&t1);
- if( IdentifierIs(t1, FINAL_TOKEN) ||
- IdentifierIs(t1, OVERRIDE_TOKEN) ||
- IdentifierIs(t1, EXPLICIT_TOKEN) ||
- IdentifierIs(t1, PROPERTY_TOKEN) )
- funcNode->AddChildLast(ParseIdentifier());
- else
- break;
- }
- }
- #ifndef AS_NO_COMPILER
- // nextToken is only modified if the current position can be interpreted as
- // type, in this case it is set to the next token after the type tokens
- bool asCParser::IsType(sToken &nextToken)
- {
- // Set a rewind point
- sToken t, t1;
- GetToken(&t);
- // A type can start with a const
- t1 = t;
- if (t1.type == ttConst)
- GetToken(&t1);
- sToken t2;
- if (t1.type != ttAuto)
- {
- // The type may be initiated with the scope operator
- if (t1.type == ttScope)
- GetToken(&t1);
- // The type may be preceded with a multilevel scope
- GetToken(&t2);
- while (t1.type == ttIdentifier)
- {
- if (t2.type == ttScope)
- {
- GetToken(&t1);
- GetToken(&t2);
- continue;
- }
- else if (t2.type == ttLessThan)
- {
- // Template types can also be used as scope identifiers
- RewindTo(&t2);
- if (CheckTemplateType(t1))
- {
- sToken t3;
- GetToken(&t3);
- if (t3.type == ttScope)
- {
- GetToken(&t1);
- GetToken(&t2);
- continue;
- }
- }
- }
- break;
- }
- RewindTo(&t2);
- }
- // 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 && t1.type != ttAuto)
- {
- RewindTo(&t);
- return false;
- }
- if (!CheckTemplateType(t1))
- {
- RewindTo(&t);
- return false;
- }
- // Object handles can be interleaved with the array brackets
- // Even though declaring variables with & is invalid we'll accept
- // it here to give an appropriate error message later
- GetToken(&t2);
- while (t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket)
- {
- if( t2.type == ttHandle )
- {
- // A handle can optionally be read-only
- sToken t3;
- GetToken(&t3);
- if(t3.type != ttConst )
- RewindTo(&t3);
- }
- else if (t2.type == ttOpenBracket)
- {
- GetToken(&t2);
- if (t2.type != ttCloseBracket)
- {
- RewindTo(&t);
- return false;
- }
- }
- GetToken(&t2);
- }
- // Return the next token so the caller can jump directly to it if desired
- nextToken = t2;
- // Rewind to start point
- RewindTo(&t);
- return true;
- }
- // This function will return true if the current token is not a template, or if it is and
- // the following has a valid syntax for a template type. The source position will be left
- // at the first token after the type in case of success
- bool asCParser::CheckTemplateType(const sToken &t)
- {
- // Is this a template type?
- tempString.Assign(&script->code[t.pos], t.length);
- if( engine->IsTemplateType(tempString.AddressOf()) )
- {
- // If the next token is a < then parse the sub-type too
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttLessThan )
- {
- RewindTo(&t1);
- return true;
- }
- for(;;)
- {
- // There might optionally be a 'const'
- GetToken(&t1);
- if( t1.type == ttConst )
- GetToken(&t1);
- // The type may be initiated with the scope operator
- if( t1.type == ttScope )
- GetToken(&t1);
- // There may be multiple levels of scope operators
- sToken t2;
- GetToken(&t2);
- while( t1.type == ttIdentifier && t2.type == ttScope )
- {
- GetToken(&t1);
- GetToken(&t2);
- }
- RewindTo(&t2);
- // Now there must be a data type
- if( !IsDataType(t1) )
- return false;
- if( !CheckTemplateType(t1) )
- return false;
- GetToken(&t1);
- // Is it a handle or array?
- while( t1.type == ttHandle || t1.type == ttOpenBracket )
- {
- if( t1.type == ttOpenBracket )
- {
- GetToken(&t1);
- if( t1.type != ttCloseBracket )
- return false;
- }
- GetToken(&t1);
- }
- // Was this the last template subtype?
- if( t1.type != ttListSeparator )
- break;
- }
- // Accept >> and >>> tokens too. But then force the tokenizer to move
- // only 1 character ahead (thus splitting the token in two).
- if( script->code[t1.pos] != '>' )
- return false;
- else if( t1.length != 1 )
- {
- // We need to break the token, so that only the first character is parsed
- SetPos(t1.pos + 1);
- }
- }
- return true;
- }
- // BNF:12: CAST ::= 'cast' '<' TYPE '>' '(' ASSIGN ')'
- asCScriptNode *asCParser::ParseCast()
- {
- asCScriptNode *node = CreateNode(snCast);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttCast )
- {
- Error(ExpectedToken("cast"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- GetToken(&t1);
- if( t1.type != ttLessThan )
- {
- Error(ExpectedToken("<"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- // Parse the data type
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttGreaterThan )
- {
- Error(ExpectedToken(">"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:11: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA
- asCScriptNode *asCParser::ParseExprValue()
- {
- asCScriptNode *node = CreateNode(snExprValue);
- if( node == 0 ) return 0;
- sToken t1, t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- // 'void' is a special expression that doesn't do anything (normally used for skipping output arguments)
- if( t1.type == ttVoid )
- node->AddChildLast(ParseToken(ttVoid));
- else if( IsRealType(t1.type) )
- node->AddChildLast(ParseConstructCall());
- else if( t1.type == ttIdentifier || t1.type == ttScope )
- {
- // Check if the expression is an anonymous function
- if( IsLambda() )
- {
- node->AddChildLast(ParseLambda());
- }
- else
- {
- // Determine the last identifier in order to check if it is a type
- sToken t;
- if( t1.type == ttScope ) t = t2; else t = t1;
- RewindTo(&t);
- GetToken(&t2);
- while( t.type == ttIdentifier )
- {
- t2 = t;
- GetToken(&t);
- if( t.type == ttScope )
- GetToken(&t);
- else
- break;
- }
- bool isDataType = IsDataType(t2);
- bool isTemplateType = false;
- if( isDataType )
- {
- // Is this a template type?
- tempString.Assign(&script->code[t2.pos], t2.length);
- if( engine->IsTemplateType(tempString.AddressOf()) )
- isTemplateType = true;
- }
- GetToken(&t2);
- // Rewind so the real parsing can be done, after deciding what to parse
- RewindTo(&t1);
- // Check if this is a construct call
- // Just 'type()' isn't considered a construct call, because type may just be a function/method name.
- // The compiler will have to sort this out, since the parser doesn't have enough information.
- if( isDataType && (t.type == ttOpenBracket && t2.type == ttCloseBracket) ) // type[]()
- node->AddChildLast(ParseConstructCall());
- else if( isTemplateType && t.type == ttLessThan ) // type<t>()
- node->AddChildLast(ParseConstructCall());
- else 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(")"), &t1);
- Error(InsteadFound(t1), &t1);
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- }
- else
- {
- Error(TXT_EXPECTED_EXPRESSION_VALUE, &t1);
- Error(InsteadFound(t1), &t1);
- }
- return node;
- }
- // BNF:12: LITERAL ::= NUMBER | STRING | BITS | 'true' | 'false' | 'null'
- // BNF:17: NUMBER ::= single token: includes integers and real numbers, same as C++
- // BNF:17: STRING ::= single token: single quoted ', double quoted ", or heredoc multi-line string """
- // BNF:17: BITS ::= single token: binary 0b or 0B, octal 0o or 0O, decimal 0d or 0D, hexadecimal 0x or 0X
- asCScriptNode *asCParser::ParseConstant()
- {
- asCScriptNode *node = CreateNode(snConstant);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( !IsConstant(t.type) )
- {
- Error(TXT_EXPECTED_CONSTANT, &t);
- Error(InsteadFound(t), &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;
- }
- bool asCParser::IsLambda()
- {
- bool isLambda = false;
- sToken t;
- GetToken(&t);
- if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) )
- {
- sToken t2;
- GetToken(&t2);
- if( t2.type == ttOpenParanthesis )
- {
- // Skip until )
- while( t2.type != ttCloseParanthesis && t2.type != ttEnd )
- GetToken(&t2);
- // The next token must be a {
- GetToken(&t2);
- if( t2.type == ttStartStatementBlock )
- isLambda = true;
- }
- }
- RewindTo(&t);
- return isLambda;
- }
- // BNF:12: LAMBDA ::= 'function' '(' [[TYPE TYPEMOD] IDENTIFIER {',' [TYPE TYPEMOD] IDENTIFIER}] ')' STATBLOCK
- asCScriptNode *asCParser::ParseLambda()
- {
- asCScriptNode *node = CreateNode(snFunction);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) )
- {
- Error(ExpectedToken("function"), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- return node;
- }
- // Parse optional type before parameter name
- if( IsType(t) && (t.type == ttAmp || t.type == ttIdentifier) )
- {
- node->AddChildLast(ParseType(true));
- if (isSyntaxError) return node;
- node->AddChildLast(ParseTypeMod(true));
- if (isSyntaxError) return node;
- }
- GetToken(&t);
- if( t.type == ttIdentifier )
- {
- RewindTo(&t);
- node->AddChildLast(ParseIdentifier());
- if (isSyntaxError) return node;
- GetToken(&t);
- while( t.type == ttListSeparator )
- {
- // Parse optional type before parameter name
- if (IsType(t) && (t.type == ttAmp || t.type == ttIdentifier))
- {
- node->AddChildLast(ParseType(true));
- if (isSyntaxError) return node;
- node->AddChildLast(ParseTypeMod(true));
- if (isSyntaxError) return node;
- }
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&t);
- }
- }
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t);
- return node;
- }
- // 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::ParseStringConstant()
- {
- asCScriptNode *node = CreateNode(snConstant);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttStringConstant && t.type != ttMultilineStringConstant && t.type != ttHeredocStringConstant )
- {
- Error(TXT_EXPECTED_STRING, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:12: FUNCCALL ::= SCOPE IDENTIFIER ARGLIST
- asCScriptNode *asCParser::ParseFunctionCall()
- {
- asCScriptNode *node = CreateNode(snFunctionCall);
- if( node == 0 ) return 0;
- // Parse scope prefix
- ParseOptionalScope(node);
- // Parse the function name followed by the argument list
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseArgList());
- return node;
- }
- // BNF:12: VARACCESS ::= SCOPE IDENTIFIER
- asCScriptNode *asCParser::ParseVariableAccess()
- {
- asCScriptNode *node = CreateNode(snVariableAccess);
- if( node == 0 ) return 0;
- // Parse scope prefix
- ParseOptionalScope(node);
- // Parse the variable name
- node->AddChildLast(ParseIdentifier());
- return node;
- }
- // BNF:11: CONSTRUCTCALL ::= TYPE ARGLIST
- asCScriptNode *asCParser::ParseConstructCall()
- {
- asCScriptNode *node = CreateNode(snConstructCall);
- if( node == 0 ) return 0;
- node->AddChildLast(ParseType(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseArgList());
- return node;
- }
- // BNF:13: ARGLIST ::= '(' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':'] ASSIGN} ')'
- asCScriptNode *asCParser::ParseArgList(bool withParenthesis)
- {
- asCScriptNode *node = CreateNode(snArgList);
- if( node == 0 ) return 0;
- sToken t1;
- if( withParenthesis )
- {
- GetToken(&t1);
- if( t1.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- }
- GetToken(&t1);
- if( t1.type == ttCloseParanthesis || t1.type == ttCloseBracket )
- {
- if( withParenthesis )
- {
- if( t1.type == ttCloseParanthesis )
- node->UpdateSourcePos(t1.pos, t1.length);
- else
- {
- asCString str;
- str.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(ttCloseBracket));
- Error(str.AddressOf(), &t1);
- }
- }
- else
- RewindTo(&t1);
- // Argument list has ended
- return node;
- }
- else
- {
- RewindTo(&t1);
- for(;;)
- {
- // Determine if this is a named argument
- sToken tl, t2;
- GetToken(&tl);
- GetToken(&t2);
- RewindTo(&tl);
- // Named arguments uses the syntax: arg : expr
- // This avoids confusion when the argument has the same name as a local variable, i.e. var = expr
- // It also avoids conflict with expressions to that creates anonymous objects initialized with lists, i.e. type = {...}
- // The alternate syntax: arg = expr, is supported to provide backwards compatibility with 2.29.0
- // TODO: 3.0.0: Remove the alternate syntax
- if( tl.type == ttIdentifier && (t2.type == ttColon || (engine->ep.alterSyntaxNamedArgs && t2.type == ttAssignment)) )
- {
- asCScriptNode *named = CreateNode(snNamedArgument);
- if( named == 0 ) return 0;
- node->AddChildLast(named);
- named->AddChildLast(ParseIdentifier());
- GetToken(&t2);
- if( engine->ep.alterSyntaxNamedArgs == 1 && t2.type == ttAssignment )
- Warning(TXT_NAMED_ARGS_WITH_OLD_SYNTAX, &t2);
- named->AddChildLast(ParseAssignment());
- }
- else
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- // Check if list continues
- GetToken(&t1);
- if( t1.type == ttListSeparator )
- continue;
- else
- {
- if( withParenthesis )
- {
- if( t1.type == ttCloseParanthesis )
- node->UpdateSourcePos(t1.pos, t1.length);
- else
- {
- Error(ExpectedTokens(")", ","), &t1);
- Error(InsteadFound(t1), &t1);
- }
- }
- else
- RewindTo(&t1);
- return node;
- }
- }
- }
- }
- 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
- // The parser doesn't have enough information about scope to determine if the
- // identifier is a datatype, so even if it happens to be the parser will
- // identify the expression as a function call rather than a construct call.
- // The compiler will sort this out later
- if( t1.type != ttIdentifier )
- {
- RewindTo(&s);
- return false;
- }
- if( t2.type == ttOpenParanthesis )
- {
- RewindTo(&s);
- return true;
- }
- RewindTo(&s);
- return false;
- }
- // BNF:13: ASSIGN ::= CONDITION [ ASSIGNOP ASSIGN ]
- asCScriptNode *asCParser::ParseAssignment()
- {
- asCScriptNode *node = CreateNode(snAssignment);
- if( node == 0 ) return 0;
- 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;
- }
- // BNF:14: CONDITION ::= EXPR ['?' ASSIGN ':' ASSIGN]
- asCScriptNode *asCParser::ParseCondition()
- {
- asCScriptNode *node = CreateNode(snCondition);
- if( node == 0 ) return 0;
- 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(":"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- }
- else
- RewindTo(&t);
- return node;
- }
- // BNF:9: EXPR ::= EXPRTERM {EXPROP EXPRTERM}
- asCScriptNode *asCParser::ParseExpression()
- {
- asCScriptNode *node = CreateNode(snExpression);
- if( node == 0 ) return 0;
- 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;
- }
- // BNF:10: EXPRTERM ::= ([TYPE '='] INITLIST) | ({EXPRPREOP} EXPRVALUE {EXPRPOSTOP})
- asCScriptNode *asCParser::ParseExprTerm()
- {
- asCScriptNode *node = CreateNode(snExprTerm);
- if( node == 0 ) return 0;
- // Check if the expression term is an initialization of a temp object with init list, i.e. type = {...}
- sToken t;
- GetToken(&t);
- sToken t2 = t, t3;
- if (IsDataType(t2) && CheckTemplateType(t2))
- {
- // The next token must be a = followed by a {
- GetToken(&t2);
- GetToken(&t3);
- if (t2.type == ttAssignment && t3.type == ttStartStatementBlock)
- {
- // It is an initialization, now parse it for real
- RewindTo(&t);
- node->AddChildLast(ParseType(false));
- GetToken(&t2);
- node->AddChildLast(ParseInitList());
- return node;
- }
- }
- // Or an anonymous init list, i.e. {...}
- else if( t.type == ttStartStatementBlock )
- {
- RewindTo(&t);
- node->AddChildLast(ParseInitList());
- return node;
- }
- // It wasn't an initialization, so it must be an ordinary expression term
- RewindTo(&t);
- for(;;)
- {
- GetToken(&t);
- RewindTo(&t);
- if( !IsPreOperator(t.type) )
- break;
- node->AddChildLast(ParseExprPreOp());
- if( isSyntaxError ) return node;
- }
- node->AddChildLast(ParseExprValue());
- if( isSyntaxError ) return node;
- for(;;)
- {
- GetToken(&t);
- RewindTo(&t);
- if( !IsPostOperator(t.type) )
- return node;
- node->AddChildLast(ParseExprPostOp());
- if( isSyntaxError ) return node;
- }
- UNREACHABLE_RETURN;
- }
- // BNF:11: EXPRPREOP ::= '-' | '+' | '!' | '++' | '--' | '~' | '@'
- asCScriptNode *asCParser::ParseExprPreOp()
- {
- asCScriptNode *node = CreateNode(snExprPreOp);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( !IsPreOperator(t.type) )
- {
- Error(TXT_EXPECTED_PRE_OPERATOR, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:11: EXPRPOSTOP ::= ('.' (FUNCCALL | IDENTIFIER)) | ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']') | ARGLIST | '++' | '--'
- asCScriptNode *asCParser::ParseExprPostOp()
- {
- asCScriptNode *node = CreateNode(snExprPostOp);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( !IsPostOperator(t.type) )
- {
- Error(TXT_EXPECTED_POST_OPERATOR, &t);
- Error(InsteadFound(t), &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(ParseArgList(false));
- GetToken(&t);
- if( t.type != ttCloseBracket )
- {
- Error(ExpectedToken("]"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- }
- else if( t.type == ttOpenParanthesis )
- {
- RewindTo(&t);
- node->AddChildLast(ParseArgList());
- }
- return node;
- }
- // BNF:15: EXPROP ::= MATHOP | COMPOP | LOGICOP | BITOP
- // BNF:16: MATHOP ::= '+' | '-' | '*' | '/' | '%' | '**'
- // BNF:16: COMPOP ::= '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | '!is'
- // BNF:16: LOGICOP ::= '&&' | '||' | '^^' | 'and' | 'or' | 'xor'
- // BNF:16: BITOP ::= '&' | '|' | '^' | '<<' | '>>' | '>>>'
- asCScriptNode *asCParser::ParseExprOperator()
- {
- asCScriptNode *node = CreateNode(snExprOperator);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( !IsOperator(t.type) )
- {
- Error(TXT_EXPECTED_OPERATOR, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:16: ASSIGNOP ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>='
- asCScriptNode *asCParser::ParseAssignOperator()
- {
- asCScriptNode *node = CreateNode(snExprOperator);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( !IsAssignOperator(t.type) )
- {
- Error(TXT_EXPECTED_OPERATOR, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- bool asCParser::IsOperator(int tokenType)
- {
- if( tokenType == ttPlus ||
- tokenType == ttMinus ||
- tokenType == ttStar ||
- tokenType == ttSlash ||
- tokenType == ttPercent ||
- tokenType == ttStarStar ||
- 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 == ttPowAssign ||
- 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 || // post increment
- tokenType == ttDec || // post decrement
- tokenType == ttDot || // member access
- tokenType == ttOpenBracket || // index operator
- tokenType == ttOpenParanthesis ) // argument list for call on function pointer
- 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;
- }
- int asCParser::ParseScript(asCScriptCode *in_script)
- {
- Reset();
- this->script = in_script;
- scriptNode = ParseScript(false);
- if( errorWhileParsing )
- return -1;
- // TODO: Should allow application to request this warning to be generated.
- // It should be off by default, since pre-processor may remove all
- // code from a section while still being meant as valid code
- /*
- // Warn in case there isn't anything in the script
- if( scriptNode->firstChild == 0 )
- {
- if( builder )
- builder->WriteWarning(script->name, TXT_SECTION_IS_EMPTY, 1, 1);
- }
- */
- return 0;
- }
- int asCParser::ParseExpression(asCScriptCode *in_script)
- {
- Reset();
- this->script = in_script;
- checkValidTypes = true;
- scriptNode = ParseExpression();
- if( errorWhileParsing )
- return -1;
- return 0;
- }
- // BNF:1: IMPORT ::= 'import' TYPE ['&'] IDENTIFIER PARAMLIST FUNCATTR 'from' STRING ';'
- asCScriptNode *asCParser::ParseImport()
- {
- asCScriptNode *node = CreateNode(snImport);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttImport )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttImport)), &t);
- Error(InsteadFound(t), &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), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- tempString.Assign(&script->code[t.pos], t.length);
- if( tempString != FROM_TOKEN )
- {
- Error(ExpectedToken(FROM_TOKEN), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttStringConstant )
- {
- Error(TXT_EXPECTED_STRING, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- asCScriptNode *mod = CreateNode(snConstant);
- if( mod == 0 ) return 0;
- node->AddChildLast(mod);
- mod->SetToken(&t);
- mod->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:0: SCRIPT ::= {IMPORT | ENUM | TYPEDEF | CLASS | MIXIN | INTERFACE | FUNCDEF | VIRTPROP | VAR | FUNC | NAMESPACE | ';'}
- asCScriptNode *asCParser::ParseScript(bool inBlock)
- {
- asCScriptNode *node = CreateNode(snScript);
- if( node == 0 ) return 0;
- // Determine type of node
- for(;;)
- {
- while( !isSyntaxError )
- {
- sToken tStart;
- GetToken(&tStart);
- // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition
- sToken t1 = tStart;
- while (IdentifierIs(t1, SHARED_TOKEN) ||
- IdentifierIs(t1, EXTERNAL_TOKEN) ||
- IdentifierIs(t1, FINAL_TOKEN) ||
- IdentifierIs(t1, ABSTRACT_TOKEN))
- GetToken(&t1);
- RewindTo(&tStart);
- 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 )
- node->AddChildLast(ParseClass());
- else if( t1.type == ttMixin )
- node->AddChildLast(ParseMixin());
- else if( t1.type == ttInterface )
- node->AddChildLast(ParseInterface());
- else if( t1.type == ttFuncDef )
- node->AddChildLast(ParseFuncDef());
- else if( t1.type == ttConst || t1.type == ttScope || t1.type == ttAuto || IsDataType(t1) )
- {
- if( IsVirtualPropertyDecl() )
- node->AddChildLast(ParseVirtualPropertyDecl(false, false));
- else if( IsVarDecl() )
- node->AddChildLast(ParseDeclaration(false, true));
- else
- node->AddChildLast(ParseFunction());
- }
- else if( t1.type == ttEndStatement )
- {
- // Ignore a semicolon by itself
- GetToken(&t1);
- }
- else if( t1.type == ttNamespace )
- node->AddChildLast(ParseNamespace());
- else if( t1.type == ttEnd )
- return node;
- else if( inBlock && t1.type == ttEndStatementBlock )
- return node;
- else
- {
- asCString str;
- const char *t = asCTokenizer::GetDefinition(t1.type);
- if( t == 0 ) t = "<unknown token>";
- str.Format(TXT_UNEXPECTED_TOKEN_s, t);
- Error(str, &t1);
- }
- }
- if( isSyntaxError )
- {
- // Search for either ';' or '{' or end
- sToken t1;
- 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;
- }
- // BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER {'::' IDENTIFIER} '{' SCRIPT '}'
- asCScriptNode *asCParser::ParseNamespace()
- {
- asCScriptNode *node = CreateNode(snNamespace);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type == ttNamespace )
- node->UpdateSourcePos(t1.pos, t1.length);
- else
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttNamespace)), &t1);
- Error(InsteadFound(t1), &t1);
- }
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- asCScriptNode *lowestNode = node;
- GetToken(&t1);
- while (t1.type == ttScope)
- {
- lowestNode->UpdateSourcePos(t1.pos, t1.length);
- asCScriptNode *scopeNode = CreateNode(snScript);
- if (scopeNode == 0)
- return 0;
- lowestNode->AddChildLast(scopeNode);
- lowestNode = CreateNode(snNamespace);
- if (lowestNode == 0)
- return 0;
- scopeNode->AddChildLast(lowestNode);
- lowestNode->AddChildLast(ParseIdentifier());
- if (isSyntaxError)
- return node;
- GetToken(&t1);
- }
-
- if( t1.type == ttStartStatementBlock )
- node->UpdateSourcePos(t1.pos, t1.length);
- else
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttStartStatementBlock)), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- sToken start = t1;
- lowestNode->AddChildLast(ParseScript(true));
- if( !isSyntaxError )
- {
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- node->UpdateSourcePos(t1.pos, t1.length);
- else
- {
- if( t1.type == ttEnd )
- Error(TXT_UNEXPECTED_END_OF_FILE, &t1);
- else
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatementBlock)), &t1);
- Error(InsteadFound(t1), &t1);
- }
- Info(TXT_WHILE_PARSING_NAMESPACE, &start);
- return node;
- }
- }
- return node;
- }
- int asCParser::ParseStatementBlock(asCScriptCode *in_script, asCScriptNode *in_block)
- {
- TimeIt("asCParser::ParseStatementBlock");
- Reset();
- // Tell the parser to validate the identifiers as valid types
- checkValidTypes = true;
- this->script = in_script;
- sourcePos = in_block->tokenPos;
- scriptNode = ParseStatementBlock();
- if( isSyntaxError || errorWhileParsing )
- return -1;
- return 0;
- }
- // BNF:1: ENUM ::= {'shared' | 'external'} 'enum' IDENTIFIER (';' | ('{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}'))
- asCScriptNode *asCParser::ParseEnumeration()
- {
- asCScriptNode *ident;
- asCScriptNode *dataType;
- asCScriptNode *node = CreateNode(snEnum);
- if( node == 0 ) return 0;
- sToken token;
- // Optional 'shared' and 'external' token
- GetToken(&token);
- while( IdentifierIs(token, SHARED_TOKEN) ||
- IdentifierIs(token, EXTERNAL_TOKEN) )
- {
- RewindTo(&token);
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&token);
- }
- // Check for enum
- if( token.type != ttEnum )
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnum)), &token);
- Error(InsteadFound(token), &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);
- Error(InsteadFound(token), &token);
- return node;
- }
- dataType = CreateNode(snDataType);
- if( dataType == 0 ) return node;
- node->AddChildLast(dataType);
- ident = CreateNode(snIdentifier);
- if( ident == 0 ) return node;
- ident->SetToken(&token);
- ident->UpdateSourcePos(token.pos, token.length);
- dataType->AddChildLast(ident);
- // External shared declarations are ended with ';'
- GetToken(&token);
- if (token.type == ttEndStatement)
- {
- RewindTo(&token);
- node->AddChildLast(ParseToken(ttEndStatement));
- return node;
- }
- // check for the start of the declaration block
- if( token.type != ttStartStatementBlock )
- {
- RewindTo(&token);
- int tokens[] = { ttStartStatementBlock, ttEndStatement };
- Error(ExpectedOneOf(tokens, 2), &token);
- Error(InsteadFound(token), &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);
- Error(InsteadFound(token), &token);
- return node;
- }
- // Add the enum element
- ident = CreateNode(snIdentifier);
- if( ident == 0 ) return node;
- ident->SetToken(&token);
- ident->UpdateSourcePos(token.pos, token.length);
- node->AddChildLast(ident);
- GetToken(&token);
- if( token.type == ttAssignment )
- {
- asCScriptNode *tmp;
- RewindTo(&token);
- tmp = SuperficiallyParseVarInit();
- 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("}"), &token);
- Error(InsteadFound(token), &token);
- return node;
- }
- return node;
- }
- 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' or 'protected'
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttPrivate && t1.type != ttProtected )
- RewindTo(&t1);
- // A variable decl starts with the type
- if (!IsType(t1))
- {
- RewindTo(&t);
- return false;
- }
- // Jump to the token after the type
- RewindTo(&t1);
- GetToken(&t1);
-
- // The declaration needs to have a name
- if( t1.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- // It can be followed by an initialization
- GetToken(&t1);
- if( t1.type == ttEndStatement || t1.type == ttAssignment || t1.type == ttListSeparator )
- {
- RewindTo(&t);
- return true;
- }
- if( t1.type == ttOpenParanthesis )
- {
- // If the closing parenthesis is followed by a statement block,
- // function decorator, or end-of-file, then treat it as a function.
- // A function decl may have nested parenthesis so we need to check
- // for this too.
- int nest = 0;
- while( t1.type != ttEnd )
- {
- if( t1.type == ttOpenParanthesis )
- nest++;
- else if( t1.type == ttCloseParanthesis )
- {
- nest--;
- if( nest == 0 )
- break;
- }
- GetToken(&t1);
- }
- if (t1.type == ttEnd)
- {
- RewindTo(&t);
- return false;
- }
- else
- {
- GetToken(&t1);
- RewindTo(&t);
- if( t1.type == ttStartStatementBlock ||
- t1.type == ttIdentifier || // function decorator
- t1.type == ttEnd )
- return false;
- }
- RewindTo(&t);
- return true;
- }
- RewindTo(&t);
- return false;
- }
- bool asCParser::IsVirtualPropertyDecl()
- {
- // Set start point so that we can rewind
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- // A class property decl can be preceded by 'private' or 'protected'
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttPrivate && t1.type != ttProtected )
- RewindTo(&t1);
- // A variable decl starts with the type
- if (!IsType(t1))
- {
- RewindTo(&t);
- return false;
- }
- // Move to the token after the type
- RewindTo(&t1);
- GetToken(&t1);
- // The decl must have an identifier
- if( t1.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- // To be a virtual property it must also have a block for the get/set functions
- GetToken(&t1);
- if( t1.type == ttStartStatementBlock )
- {
- 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);
- if( isMethod )
- {
- // A class method decl can be preceded by 'private' or 'protected'
- sToken t1, t2;
- GetToken(&t1);
- if( t1.type != ttPrivate && t1.type != ttProtected )
- RewindTo(&t1);
- // A class constructor starts with identifier followed by parenthesis
- // A class destructor starts with the ~ token
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- if( (t1.type == ttIdentifier && t2.type == ttOpenParanthesis) || t1.type == ttBitNot )
- {
- RewindTo(&t);
- return true;
- }
- }
- // A function decl starts with a type
- sToken t1;
- if (!IsType(t1))
- {
- RewindTo(&t);
- return false;
- }
- // Move to the token after the type
- RewindTo(&t1);
- GetToken(&t1);
- // There can be an ampersand if the function returns a reference
- if( t1.type == ttAmp )
- {
- RewindTo(&t);
- return true;
- }
- if( t1.type != ttIdentifier )
- {
- RewindTo(&t);
- return false;
- }
- GetToken(&t1);
- if( t1.type == ttOpenParanthesis )
- {
- // If the closing parenthesis is not followed by a
- // statement block then it is not a function.
- // It's possible that there are nested parenthesis due to default
- // arguments so this should be checked for.
- int nest = 0;
- GetToken(&t1);
- while( (nest || t1.type != ttCloseParanthesis) && t1.type != ttEnd )
- {
- if( t1.type == ttOpenParanthesis )
- nest++;
- if( t1.type == ttCloseParanthesis )
- nest--;
- GetToken(&t1);
- }
- if( t1.type == ttEnd )
- return false;
- else
- {
- if( isMethod )
- {
- // A class method can have a 'const' token after the parameter list
- GetToken(&t1);
- if( t1.type != ttConst )
- RewindTo(&t1);
- }
- // A function may also have any number of additional attributes
- for( ; ; )
- {
- GetToken(&t1);
- if( !IdentifierIs(t1, FINAL_TOKEN) &&
- !IdentifierIs(t1, OVERRIDE_TOKEN) &&
- !IdentifierIs(t1, EXPLICIT_TOKEN) &&
- !IdentifierIs(t1, PROPERTY_TOKEN) )
- {
- RewindTo(&t1);
- break;
- }
- }
-
- GetToken(&t1);
- RewindTo(&t);
- if( t1.type == ttStartStatementBlock )
- return true;
- }
- RewindTo(&t);
- return false;
- }
- RewindTo(&t);
- return false;
- }
- // BNF:1: FUNCDEF ::= {'external' | 'shared'} 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';'
- asCScriptNode *asCParser::ParseFuncDef()
- {
- asCScriptNode *node = CreateNode(snFuncDef);
- if( node == 0 ) return 0;
- // Allow keywords 'external' and 'shared' before 'interface'
- sToken t1;
- GetToken(&t1);
- while (IdentifierIs(t1, SHARED_TOKEN) ||
- IdentifierIs(t1, EXTERNAL_TOKEN))
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- if (isSyntaxError) return node;
- GetToken(&t1);
- }
- if( t1.type != ttFuncDef )
- {
- Error(asCTokenizer::GetDefinition(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(asCTokenizer::GetDefinition(ttEndStatement)), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:1: FUNC ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] FUNCATTR (';' | STATBLOCK)
- asCScriptNode *asCParser::ParseFunction(bool isMethod)
- {
- asCScriptNode *node = CreateNode(snFunction);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if (!isMethod)
- {
- // A global function can be marked as shared and external
- while (t1.type == ttIdentifier)
- {
- if (IdentifierIs(t1, SHARED_TOKEN) ||
- IdentifierIs(t1, EXTERNAL_TOKEN))
- {
- RewindTo(&t1);
- node->AddChildLast(ParseIdentifier());
- if (isSyntaxError) return node;
- }
- else
- break;
- GetToken(&t1);
- }
- }
- // A class method can start with 'private' or 'protected'
- if (isMethod && t1.type == ttPrivate)
- {
- RewindTo(&t1);
- node->AddChildLast(ParseToken(ttPrivate));
- GetToken(&t1);
- }
- else if (isMethod && t1.type == ttProtected)
- {
- RewindTo(&t1);
- node->AddChildLast(ParseToken(ttProtected));
- GetToken(&t1);
- }
- if( isSyntaxError ) return node;
- // If it is a global function, or a method, except constructor and destructor, then the return type is parsed
- sToken t2;
- GetToken(&t2);
- RewindTo(&t1);
- 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 )
- {
- GetToken(&t1);
- RewindTo(&t1);
- // Is the method a const?
- if( t1.type == ttConst )
- node->AddChildLast(ParseToken(ttConst));
- }
- // TODO: Should support abstract methods, in which case no statement block should be provided
- ParseMethodAttributes(node);
- if( isSyntaxError ) return node;
- // External shared functions must be ended with ';'
- GetToken(&t1);
- RewindTo(&t1);
- if (t1.type == ttEndStatement)
- {
- node->AddChildLast(ParseToken(ttEndStatement));
- return node;
- }
- // 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;
- }
- // BNF:2: INTFMTHD ::= TYPE ['&'] IDENTIFIER PARAMLIST ['const'] ';'
- asCScriptNode *asCParser::ParseInterfaceMethod()
- {
- asCScriptNode *node = CreateNode(snFunction);
- if( node == 0 ) return 0;
- 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(";"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:1: VIRTPROP ::= ['private' | 'protected'] TYPE ['&'] IDENTIFIER '{' {('get' | 'set') ['const'] FUNCATTR (STATBLOCK | ';')} '}'
- asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterface)
- {
- asCScriptNode *node = CreateNode(snVirtualProperty);
- if( node == 0 ) return 0;
- sToken t1,t2;
- GetToken(&t1);
- GetToken(&t2);
- RewindTo(&t1);
- // A class method can start with 'private' or 'protected'
- if( isMethod && t1.type == ttPrivate )
- node->AddChildLast(ParseToken(ttPrivate));
- else if( isMethod && t1.type == ttProtected )
- node->AddChildLast(ParseToken(ttProtected));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseType(true));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseTypeMod(false));
- if( isSyntaxError ) return node;
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- for(;;)
- {
- GetToken(&t1);
- asCScriptNode *accessorNode = 0;
- if( IdentifierIs(t1, GET_TOKEN) || IdentifierIs(t1, SET_TOKEN) )
- {
- accessorNode = CreateNode(snVirtualProperty);
- if( accessorNode == 0 ) return 0;
- node->AddChildLast(accessorNode);
- RewindTo(&t1);
- accessorNode->AddChildLast(ParseIdentifier());
- if( isMethod )
- {
- GetToken(&t1);
- RewindTo(&t1);
- if( t1.type == ttConst )
- accessorNode->AddChildLast(ParseToken(ttConst));
- if( !isInterface )
- {
- ParseMethodAttributes(accessorNode);
- if( isSyntaxError ) return node;
- }
- }
- if( !isInterface )
- {
- GetToken(&t1);
- if( t1.type == ttStartStatementBlock )
- {
- RewindTo(&t1);
- accessorNode->AddChildLast(SuperficiallyParseStatementBlock());
- if( isSyntaxError ) return node;
- }
- else if( t1.type != ttEndStatement )
- {
- Error(ExpectedTokens(";", "{"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- }
- else
- {
- GetToken(&t1);
- if( t1.type != ttEndStatement )
- {
- Error(ExpectedToken(";"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- }
- }
- else if( t1.type == ttEndStatementBlock )
- break;
- else
- {
- const char *tokens[] = { GET_TOKEN, SET_TOKEN, asCTokenizer::GetDefinition(ttEndStatementBlock) };
- Error(ExpectedOneOf(tokens, 3), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- }
- return node;
- }
- // BNF:1: INTERFACE ::= {'external' | 'shared'} 'interface' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}'))
- asCScriptNode *asCParser::ParseInterface()
- {
- asCScriptNode *node = CreateNode(snInterface);
- if( node == 0 ) return 0;
- sToken t;
- // Allow keywords 'external' and 'shared' before 'interface'
- GetToken(&t);
- while( IdentifierIs(t, SHARED_TOKEN) ||
- IdentifierIs(t, EXTERNAL_TOKEN) )
- {
- RewindTo(&t);
- node->AddChildLast(ParseIdentifier());
- if (isSyntaxError) return node;
- GetToken(&t);
- }
- if( t.type != ttInterface )
- {
- Error(ExpectedToken("interface"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- node->AddChildLast(ParseIdentifier());
- // External shared declarations are ended with ';'
- GetToken(&t);
- if (t.type == ttEndStatement)
- {
- RewindTo(&t);
- node->AddChildLast(ParseToken(ttEndStatement));
- return node;
- }
- // Can optionally have a list of interfaces that are inherited
- if( t.type == ttColon )
- {
- asCScriptNode *inherit = CreateNode(snIdentifier);
- node->AddChildLast(inherit);
- ParseOptionalScope(inherit);
- inherit->AddChildLast(ParseIdentifier());
- GetToken(&t);
- while( t.type == ttListSeparator )
- {
- inherit = CreateNode(snIdentifier);
- node->AddChildLast(inherit);
- ParseOptionalScope(inherit);
- inherit->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- }
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- // Parse interface methods
- GetToken(&t);
- RewindTo(&t);
- while( t.type != ttEndStatementBlock && t.type != ttEnd )
- {
- if( IsVirtualPropertyDecl() )
- node->AddChildLast(ParseVirtualPropertyDecl(true, true));
- else if( t.type == ttEndStatement )
- // Skip empty declarations
- GetToken(&t);
- else
- // Parse the method signature
- node->AddChildLast(ParseInterfaceMethod());
- if( isSyntaxError ) return node;
- GetToken(&t);
- RewindTo(&t);
- }
- GetToken(&t);
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:1: MIXIN ::= 'mixin' CLASS
- asCScriptNode *asCParser::ParseMixin()
- {
- asCScriptNode *node = CreateNode(snMixin);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttMixin )
- {
- Error(ExpectedToken("mixin"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->SetToken(&t);
- // A mixin token must be followed by a class declaration
- node->AddChildLast(ParseClass());
- return node;
- }
- // BNF:1: CLASS ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR | FUNCDEF} '}'))
- asCScriptNode *asCParser::ParseClass()
- {
- asCScriptNode *node = CreateNode(snClass);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- // Allow the keywords 'shared', 'abstract', 'final', and 'external' before 'class'
- while( IdentifierIs(t, SHARED_TOKEN) ||
- IdentifierIs(t, ABSTRACT_TOKEN) ||
- IdentifierIs(t, FINAL_TOKEN) ||
- IdentifierIs(t, EXTERNAL_TOKEN) )
- {
- RewindTo(&t);
- node->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- if( t.type != ttClass )
- {
- Error(ExpectedToken("class"), &t);
- Error(InsteadFound(t), &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());
- // External shared declarations are ended with ';'
- GetToken(&t);
- if (t.type == ttEndStatement)
- {
- RewindTo(&t);
- node->AddChildLast(ParseToken(ttEndStatement));
- return node;
- }
- // Optional list of interfaces that are being implemented and classes that are being inherited
- if( t.type == ttColon )
- {
- asCScriptNode *inherit = CreateNode(snIdentifier);
- node->AddChildLast(inherit);
- ParseOptionalScope(inherit);
- inherit->AddChildLast(ParseIdentifier());
- GetToken(&t);
- while( t.type == ttListSeparator )
- {
- inherit = CreateNode(snIdentifier);
- node->AddChildLast(inherit);
- ParseOptionalScope(inherit);
- inherit->AddChildLast(ParseIdentifier());
- GetToken(&t);
- }
- }
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- // Parse properties
- GetToken(&t);
- RewindTo(&t);
- while( t.type != ttEndStatementBlock && t.type != ttEnd )
- {
- // Is it a property or a method?
- if (t.type == ttFuncDef)
- node->AddChildLast(ParseFuncDef());
- else if( IsFuncDecl(true) )
- node->AddChildLast(ParseFunction(true));
- else if( IsVirtualPropertyDecl() )
- node->AddChildLast(ParseVirtualPropertyDecl(true, false));
- else if( IsVarDecl() )
- node->AddChildLast(ParseDeclaration(true));
- else if( t.type == ttEndStatement )
- // Skip empty declarations
- GetToken(&t);
- else
- {
- Error(TXT_EXPECTED_METHOD_OR_PROPERTY, &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- if( isSyntaxError )
- return node;
- GetToken(&t);
- RewindTo(&t);
- }
- GetToken(&t);
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- int asCParser::ParseVarInit(asCScriptCode *in_script, asCScriptNode *in_init)
- {
- Reset();
- // Tell the parser to validate the identifiers as valid types
- checkValidTypes = true;
- this->script = in_script;
- sourcePos = in_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), &t);
- Error(InsteadFound(t), &t);
- }
- // Don't allow any more tokens after the expression
- GetToken(&t);
- if( t.type != ttEnd && t.type != ttEndStatement && t.type != ttListSeparator && t.type != ttEndStatementBlock )
- {
- asCString msg;
- msg.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(t.type));
- Error(msg, &t);
- }
- if( isSyntaxError || errorWhileParsing )
- return -1;
- return 0;
- }
- asCScriptNode *asCParser::SuperficiallyParseVarInit()
- {
- asCScriptNode *node = CreateNode(snAssignment);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- node->UpdateSourcePos(t.pos, t.length);
- if( t.type == ttAssignment )
- {
- GetToken(&t);
- sToken start = t;
- // Find the end of the expression
- int indentParan = 0;
- int indentBrace = 0;
- while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) )
- {
- if( t.type == ttOpenParanthesis )
- indentParan++;
- else if( t.type == ttCloseParanthesis )
- indentParan--;
- else if( t.type == ttStartStatementBlock )
- indentBrace++;
- else if( t.type == ttEndStatementBlock )
- indentBrace--;
- else if( t.type == ttNonTerminatedStringConstant )
- {
- Error(TXT_NONTERMINATED_STRING, &t);
- break;
- }
- else if( t.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- Info(TXT_WHILE_PARSING_EXPRESSION, &start);
- 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 )
- {
- sToken start = t;
- // 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 == ttNonTerminatedStringConstant )
- {
- Error(TXT_NONTERMINATED_STRING, &t);
- break;
- }
- else if( t.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t);
- Info(TXT_WHILE_PARSING_ARG_LIST, &start);
- break;
- }
- }
- }
- else
- {
- int tokens[] = {ttAssignment, ttOpenParanthesis};
- Error(ExpectedOneOf(tokens, 2), &t);
- Error(InsteadFound(t), &t);
- }
- return node;
- }
- asCScriptNode *asCParser::SuperficiallyParseStatementBlock()
- {
- asCScriptNode *node = CreateNode(snStatementBlock);
- if( node == 0 ) return 0;
- // 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("{"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- sToken start = t1;
- int level = 1;
- while( level > 0 && !isSyntaxError )
- {
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- level--;
- else if( t1.type == ttStartStatementBlock )
- level++;
- else if( t1.type == ttNonTerminatedStringConstant )
- {
- Error(TXT_NONTERMINATED_STRING, &t1);
- break;
- }
- else if( t1.type == ttEnd )
- {
- Error(TXT_UNEXPECTED_END_OF_FILE, &t1);
- Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start);
- break;
- }
- }
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- // BNF:2: STATBLOCK ::= '{' {VAR | STATEMENT} '}'
- asCScriptNode *asCParser::ParseStatementBlock()
- {
- asCScriptNode *node = CreateNode(snStatementBlock);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- sToken start = t1;
- 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);
- Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start);
- return node;
- }
- isSyntaxError = false;
- }
- }
- UNREACHABLE_RETURN;
- }
- // BNF:4: INITLIST ::= '{' [ASSIGN | INITLIST] {',' [ASSIGN | INITLIST]} '}'
- asCScriptNode *asCParser::ParseInitList()
- {
- asCScriptNode *node = CreateNode(snInitList);
- if( node == 0 ) return 0;
- sToken t1;
- GetToken(&t1);
- if( t1.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t1);
- Error(InsteadFound(t1), &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(CreateNode(snUndefined));
- node->lastChild->UpdateSourcePos(t1.pos, 1);
- GetToken(&t1);
- if( t1.type == ttEndStatementBlock )
- {
- // No expression
- node->AddChildLast(CreateNode(snUndefined));
- node->lastChild->UpdateSourcePos(t1.pos, 1);
- node->UpdateSourcePos(t1.pos, t1.length);
- return node;
- }
- RewindTo(&t1);
- }
- else if( t1.type == ttEndStatementBlock )
- {
- // No expression
- node->AddChildLast(CreateNode(snUndefined));
- node->lastChild->UpdateSourcePos(t1.pos, 1);
- 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("}", ","), &t1);
- Error(InsteadFound(t1), &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("}", ","), &t1);
- Error(InsteadFound(t1), &t1);
- return node;
- }
- }
- }
- }
- UNREACHABLE_RETURN;
- }
- // BNF:1: VAR ::= ['private'|'protected'] TYPE IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST] {',' IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST]} ';'
- asCScriptNode *asCParser::ParseDeclaration(bool isClassProp, bool isGlobalVar)
- {
- asCScriptNode *node = CreateNode(snDeclaration);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- RewindTo(&t);
- // A class property can be preceeded by private
- if( t.type == ttPrivate && isClassProp )
- node->AddChildLast(ParseToken(ttPrivate));
- else if( t.type == ttProtected && isClassProp )
- node->AddChildLast(ParseToken(ttProtected));
- // Parse data type
- node->AddChildLast(ParseType(true, false, !isClassProp));
- if( isSyntaxError ) return node;
- for(;;)
- {
- // Parse identifier
- node->AddChildLast(ParseIdentifier());
- if( isSyntaxError ) return node;
- if( isClassProp || isGlobalVar )
- {
- // Only superficially parse the initialization info for the class property
- GetToken(&t);
- RewindTo(&t);
- if( t.type == ttAssignment || t.type == ttOpenParanthesis )
- {
- node->AddChildLast(SuperficiallyParseVarInit());
- if( isSyntaxError ) return node;
- }
- }
- else
- {
- // 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(",", ";"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- }
- UNREACHABLE_RETURN;
- }
- // BNF:7: STATEMENT ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT | TRY)
- 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 if (t1.type == ttTry)
- return ParseTryCatch();
- else
- {
- if( IsVarDecl() )
- {
- Error(TXT_UNEXPECTED_VAR_DECL, &t1);
- return 0;
- }
- return ParseExpressionStatement();
- }
- }
- // BNF:8: EXPRSTAT ::= [ASSIGN] ';'
- asCScriptNode *asCParser::ParseExpressionStatement()
- {
- asCScriptNode *node = CreateNode(snExpressionStatement);
- if( node == 0 ) return 0;
- 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(";"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:8: SWITCH ::= 'switch' '(' ASSIGN ')' '{' {CASE} '}'
- asCScriptNode *asCParser::ParseSwitch()
- {
- asCScriptNode *node = CreateNode(snSwitch);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttSwitch )
- {
- Error(ExpectedToken("switch"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttStartStatementBlock )
- {
- Error(ExpectedToken("{"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- while( !isSyntaxError )
- {
- GetToken(&t);
- if( t.type == ttEndStatementBlock )
- break;
- RewindTo(&t);
- if( t.type != ttCase && t.type != ttDefault )
- {
- const char *tokens[] = {"case", "default"};
- Error(ExpectedOneOf(tokens, 2), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseCase());
- if( isSyntaxError ) return node;
- }
- if( t.type != ttEndStatementBlock )
- {
- Error(ExpectedToken("}"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- return node;
- }
- // BNF:9: CASE ::= (('case' EXPR) | 'default') ':' {STATEMENT}
- asCScriptNode *asCParser::ParseCase()
- {
- asCScriptNode *node = CreateNode(snCase);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttCase && t.type != ttDefault )
- {
- Error(ExpectedTokens("case", "default"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- if(t.type == ttCase)
- {
- node->AddChildLast(ParseExpression());
- }
- GetToken(&t);
- if( t.type != ttColon )
- {
- Error(ExpectedToken(":"), &t);
- Error(InsteadFound(t), &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;
- }
- // BNF:8: IF ::= 'if' '(' ASSIGN ')' STATEMENT ['else' STATEMENT]
- asCScriptNode *asCParser::ParseIf()
- {
- asCScriptNode *node = CreateNode(snIf);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttIf )
- {
- Error(ExpectedToken("if"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t);
- Error(InsteadFound(t), &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;
- }
- // BNF:8: TRY ::= 'try' STATBLOCK 'catch' STATBLOCK
- asCScriptNode *asCParser::ParseTryCatch()
- {
- asCScriptNode *node = CreateNode(snTryCatch);
- if (node == 0) return 0;
- sToken t;
- GetToken(&t);
- if (t.type != ttTry)
- {
- Error(ExpectedToken("try"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- node->AddChildLast(ParseStatementBlock());
- if (isSyntaxError) return node;
- GetToken(&t);
- if (t.type != ttCatch)
- {
- Error(ExpectedToken("catch"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseStatementBlock());
- if (isSyntaxError) return node;
- return node;
- }
- // BNF:8: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT
- asCScriptNode *asCParser::ParseFor()
- {
- asCScriptNode *node = CreateNode(snFor);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttFor )
- {
- Error(ExpectedToken("for"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- Error(InsteadFound(t), &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);
- // Parse N increment statements separated by ,
- for(;;)
- {
- asCScriptNode *n = CreateNode(snExpressionStatement);
- if( n == 0 ) return 0;
- node->AddChildLast(n);
- n->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type == ttListSeparator )
- continue;
- else if( t.type == ttCloseParanthesis )
- break;
- else
- {
- const char *tokens[] = {",", ")"};
- Error(ExpectedOneOf(tokens, 2), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- }
- }
- node->AddChildLast(ParseStatement());
- return node;
- }
- // BNF:8: WHILE ::= 'while' '(' ASSIGN ')' STATEMENT
- asCScriptNode *asCParser::ParseWhile()
- {
- asCScriptNode *node = CreateNode(snWhile);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttWhile )
- {
- Error(ExpectedToken("while"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseStatement());
- return node;
- }
- // BNF:8: DOWHILE ::= 'do' STATEMENT 'while' '(' ASSIGN ')' ';'
- asCScriptNode *asCParser::ParseDoWhile()
- {
- asCScriptNode *node = CreateNode(snDoWhile);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttDo )
- {
- Error(ExpectedToken("do"), &t);
- Error(InsteadFound(t), &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"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttOpenParanthesis )
- {
- Error(ExpectedToken("("), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->AddChildLast(ParseAssignment());
- if( isSyntaxError ) return node;
- GetToken(&t);
- if( t.type != ttCloseParanthesis )
- {
- Error(ExpectedToken(")"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:8: RETURN ::= 'return' [ASSIGN] ';'
- asCScriptNode *asCParser::ParseReturn()
- {
- asCScriptNode *node = CreateNode(snReturn);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttReturn )
- {
- Error(ExpectedToken("return"), &t);
- Error(InsteadFound(t), &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(";"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:8: BREAK ::= 'break' ';'
- asCScriptNode *asCParser::ParseBreak()
- {
- asCScriptNode *node = CreateNode(snBreak);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttBreak )
- {
- Error(ExpectedToken("break"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";"), &t);
- Error(InsteadFound(t), &t);
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // BNF:8: CONTINUE ::= 'continue' ';'
- asCScriptNode *asCParser::ParseContinue()
- {
- asCScriptNode *node = CreateNode(snContinue);
- if( node == 0 ) return 0;
- sToken t;
- GetToken(&t);
- if( t.type != ttContinue )
- {
- Error(ExpectedToken("continue"), &t);
- Error(InsteadFound(t), &t);
- return node;
- }
- node->UpdateSourcePos(t.pos, t.length);
- GetToken(&t);
- if( t.type != ttEndStatement )
- {
- Error(ExpectedToken(";"), &t);
- Error(InsteadFound(t), &t);
- }
- node->UpdateSourcePos(t.pos, t.length);
- return node;
- }
- // TODO: typedef: Typedefs should accept complex types as well
- // BNF:1: TYPEDEF ::= 'typedef' PRIMTYPE IDENTIFIER ';'
- asCScriptNode *asCParser::ParseTypedef()
- {
- // Create the typedef node
- asCScriptNode *node = CreateNode(snTypedef);
- if( node == 0 ) return 0;
- sToken token;
- GetToken(&token);
- if( token.type != ttTypedef)
- {
- Error(ExpectedToken(asCTokenizer::GetDefinition(ttTypedef)), &token);
- Error(InsteadFound(token), &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, asCTokenizer::GetDefinition(token.type));
- Error(str, &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(asCTokenizer::GetDefinition(token.type)), &token);
- Error(InsteadFound(token), &token);
- }
- return node;
- }
- #endif
- END_AS_NAMESPACE
|