1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561 |
- /*
- 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
- andreas@angelcode.com
- */
- //
- // 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
|