as_compiler.cpp 462 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2015 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Oorni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() pow()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. #include "as_context.h" // as_powi()
  40. BEGIN_AS_NAMESPACE
  41. //
  42. // The calling convention rules for script functions:
  43. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  44. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  45. // - The object pointer is always passed as the first argument, position 0
  46. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  47. //
  48. // TODO: I must correct the interpretation of a references to objects in the compiler.
  49. // A reference should mean that a pointer to the object is on the stack.
  50. // No expression should end up as non-references to objects, as the actual object is
  51. // never put on the stack.
  52. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  53. // Function parameters of called functions can also be non-references, but in that case it means the
  54. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  55. //
  56. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  57. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  58. // is currently stored, i.e. in variable, in register, on stack, etc.
  59. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  60. {
  61. builder = 0;
  62. script = 0;
  63. variables = 0;
  64. isProcessingDeferredParams = false;
  65. isCompilingDefaultArg = false;
  66. noCodeOutput = 0;
  67. }
  68. asCCompiler::~asCCompiler()
  69. {
  70. while( variables )
  71. {
  72. asCVariableScope *var = variables;
  73. variables = variables->parent;
  74. asDELETE(var,asCVariableScope);
  75. }
  76. }
  77. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  78. {
  79. this->builder = builder;
  80. this->engine = builder->engine;
  81. this->script = script;
  82. this->outFunc = outFunc;
  83. hasCompileErrors = false;
  84. m_isConstructor = false;
  85. m_isConstructorCalled = false;
  86. m_classDecl = 0;
  87. m_globalVar = 0;
  88. nextLabel = 0;
  89. breakLabels.SetLength(0);
  90. continueLabels.SetLength(0);
  91. numLambdas = 0;
  92. byteCode.ClearAll();
  93. }
  94. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  95. {
  96. Reset(builder, script, outFunc);
  97. m_classDecl = classDecl;
  98. // Insert a JitEntry at the start of the function for JIT compilers
  99. byteCode.InstrPTR(asBC_JitEntry, 0);
  100. // Add a variable scope that might be needed to declare dummy variables
  101. // in case the member initialization refers to undefined symbols.
  102. AddVariableScope();
  103. // Initialize the class members that have no explicit expression first. This will allow the
  104. // base class' constructor to access these members without worry they will be uninitialized.
  105. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  106. CompileMemberInitialization(&byteCode, true);
  107. // If the class is derived from another, then the base class' default constructor must be called
  108. if( outFunc->objectType->derivedFrom )
  109. {
  110. // Make sure the base class really has a default constructor
  111. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  112. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node);
  113. // Call the base class' default constructor
  114. byteCode.InstrSHORT(asBC_PSF, 0);
  115. byteCode.Instr(asBC_RDSPtr);
  116. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  117. }
  118. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  119. // to access the base class members without worry they will be uninitialized
  120. CompileMemberInitialization(&byteCode, false);
  121. byteCode.OptimizeLocally(tempVariableOffsets);
  122. // If there are compile errors, there is no reason to build the final code
  123. if( hasCompileErrors )
  124. return -1;
  125. // Pop the object pointer from the stack
  126. byteCode.Ret(AS_PTR_SIZE);
  127. // Count total variable size
  128. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  129. outFunc->scriptData->variableSpace = varSize;
  130. FinalizeFunction();
  131. #ifdef AS_DEBUG
  132. // DEBUG: output byte code
  133. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc);
  134. #endif
  135. return 0;
  136. }
  137. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  138. {
  139. Reset(builder, script, outFunc);
  140. // Insert a JitEntry at the start of the function for JIT compilers
  141. byteCode.InstrPTR(asBC_JitEntry, 0);
  142. // Find the corresponding constructor
  143. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  144. int constructor = 0;
  145. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  146. {
  147. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  148. {
  149. constructor = dt.GetBehaviour()->constructors[n];
  150. break;
  151. }
  152. }
  153. // Allocate the class and instantiate it with the constructor
  154. int varOffset = AllocateVariable(dt, true);
  155. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  156. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  157. // Copy all arguments to the top of the stack
  158. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  159. int offset = (int)outFunc->GetSpaceNeededForArguments();
  160. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  161. {
  162. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  163. outFunc->parameterTypes[a].IsReference() )
  164. {
  165. offset -= AS_PTR_SIZE;
  166. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  167. }
  168. else
  169. {
  170. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  171. {
  172. offset -= 2;
  173. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  174. }
  175. else
  176. {
  177. offset -= 1;
  178. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  179. }
  180. }
  181. }
  182. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  183. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  184. // Return a handle to the newly created object
  185. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  186. byteCode.Ret(argDwords);
  187. FinalizeFunction();
  188. // Tell the virtual machine not to clean up parameters on exception
  189. outFunc->dontCleanUpOnException = true;
  190. /*
  191. #ifdef AS_DEBUG
  192. // DEBUG: output byte code
  193. asCString args;
  194. args.Format("%d", outFunc->parameterTypes.GetLength());
  195. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  196. #endif
  197. */
  198. return 0;
  199. }
  200. void asCCompiler::FinalizeFunction()
  201. {
  202. TimeIt("asCCompiler::FinalizeFunction");
  203. asASSERT( outFunc->scriptData );
  204. asUINT n;
  205. // Finalize the bytecode
  206. byteCode.Finalize(tempVariableOffsets);
  207. byteCode.ExtractObjectVariableInfo(outFunc);
  208. // Compile the list of object variables for the exception handler
  209. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  210. for( n = 0; n < variableAllocations.GetLength(); n++ )
  211. {
  212. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  213. {
  214. if( variableIsOnHeap[n] )
  215. {
  216. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  217. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  218. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  219. }
  220. }
  221. }
  222. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  223. for( n = 0; n < variableAllocations.GetLength(); n++ )
  224. {
  225. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  226. {
  227. if( !variableIsOnHeap[n] )
  228. {
  229. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  230. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  231. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  232. }
  233. }
  234. }
  235. // Copy byte code to the function
  236. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  237. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  238. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  239. outFunc->AddReferences();
  240. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  241. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  242. // Extract the script section indexes too if there are any entries that are different from the function's script section
  243. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  244. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  245. {
  246. if( byteCode.sectionIdxs[n] != lastIdx )
  247. {
  248. lastIdx = byteCode.sectionIdxs[n];
  249. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  250. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  251. }
  252. }
  253. }
  254. // internal
  255. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  256. {
  257. int stackPos = 0;
  258. if( outFunc->objectType )
  259. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  260. // Add the first variable scope, which the parameters and
  261. // variables declared in the outermost statement block is
  262. // part of.
  263. AddVariableScope();
  264. bool isDestructor = false;
  265. asCDataType returnType;
  266. // Examine return type
  267. returnType = outFunc->returnType;
  268. // Check if this is a constructor or destructor
  269. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  270. {
  271. if( outFunc->name[0] == '~' )
  272. isDestructor = true;
  273. else if( outFunc->objectType->name == outFunc->name )
  274. m_isConstructor = true;
  275. }
  276. // Is the return type allowed?
  277. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  278. !returnType.CanBeInstantiated() )
  279. {
  280. // TODO: Hasn't this been validated by the builder already?
  281. asCString str;
  282. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  283. Error(str, func);
  284. }
  285. // If the return type is a value type returned by value the address of the
  286. // location where the value will be stored is pushed on the stack before
  287. // the arguments
  288. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  289. stackPos -= AS_PTR_SIZE;
  290. asCVariableScope vs(0);
  291. // Declare parameters
  292. asUINT n;
  293. for( n = 0; n < parameterNames.GetLength(); n++ )
  294. {
  295. // Get the parameter type
  296. asCDataType &type = outFunc->parameterTypes[n];
  297. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  298. // Is the data type allowed?
  299. // TODO: Hasn't this been validated by the builder already?
  300. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  301. (!type.IsReference() && !type.CanBeInstantiated()) )
  302. {
  303. asCString parm = type.Format(outFunc->nameSpace);
  304. if( inoutFlag == asTM_INREF )
  305. parm += "in";
  306. else if( inoutFlag == asTM_OUTREF )
  307. parm += "out";
  308. asCString str;
  309. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  310. Error(str, func);
  311. }
  312. // If the parameter has a name then declare it as variable
  313. if( parameterNames[n] != "" )
  314. {
  315. asCString &name = parameterNames[n];
  316. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  317. {
  318. // TODO: It might be an out-of-memory too
  319. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  320. }
  321. // Add marker for variable declaration
  322. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  323. outFunc->AddVariable(name, type, stackPos);
  324. }
  325. else
  326. vs.DeclareVariable("", type, stackPos, true);
  327. // Move to next parameter
  328. stackPos -= type.GetSizeOnStackDWords();
  329. }
  330. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  331. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  332. variables->DeclareVariable("return", returnType, stackPos, true);
  333. return stackPos;
  334. }
  335. void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
  336. {
  337. asASSERT( m_classDecl );
  338. // Initialize each member in the order they were declared
  339. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  340. {
  341. asCObjectProperty *prop = outFunc->objectType->properties[n];
  342. // Check if the property has an initialization expression
  343. asCScriptNode *declNode = 0;
  344. asCScriptNode *initNode = 0;
  345. asCScriptCode *initScript = 0;
  346. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  347. {
  348. if( m_classDecl->propInits[m].name == prop->name )
  349. {
  350. declNode = m_classDecl->propInits[m].declNode;
  351. initNode = m_classDecl->propInits[m].initNode;
  352. initScript = m_classDecl->propInits[m].file;
  353. break;
  354. }
  355. }
  356. // If declNode is null, the property was inherited in which case
  357. // it was already initialized by the base class' constructor
  358. if( declNode )
  359. {
  360. if( initNode )
  361. {
  362. if( onlyDefaults )
  363. continue;
  364. #ifdef AS_NO_MEMBER_INIT
  365. // Give an error as the initialization in the declaration has been disabled
  366. asCScriptCode *origScript = script;
  367. script = initScript;
  368. Error("Initialization of members in declaration is not supported", initNode);
  369. script = origScript;
  370. // Clear the initialization node
  371. initNode = 0;
  372. initScript = script;
  373. #else
  374. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  375. asCParser parser(builder);
  376. int r = parser.ParseVarInit(initScript, initNode);
  377. if( r < 0 )
  378. continue;
  379. initNode = parser.GetScriptNode();
  380. #endif
  381. }
  382. else
  383. {
  384. if( !onlyDefaults )
  385. continue;
  386. }
  387. #ifdef AS_NO_MEMBER_INIT
  388. // The initialization will be done in the asCScriptObject constructor, so
  389. // here we should just validate that the member has a default constructor
  390. if( prop->type.IsObject() &&
  391. !prop->type.IsObjectHandle() &&
  392. (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
  393. prop->type.GetBehaviour()->factory == 0) ||
  394. ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
  395. prop->type.GetBehaviour()->construct == 0 &&
  396. !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
  397. {
  398. // Class has no default factory/constructor.
  399. asCString str;
  400. // TODO: funcdef: asCDataType should have a GetTypeName()
  401. if( prop->type.GetFuncDef() )
  402. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  403. else
  404. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
  405. Error(str, declNode);
  406. }
  407. #else
  408. // Temporarily set the script that is being compiled to where the member initialization is declared.
  409. // The script can be different when including mixin classes from a different script section
  410. asCScriptCode *origScript = script;
  411. script = initScript;
  412. // Add a line instruction with the position of the declaration
  413. LineInstr(byteCode, declNode->tokenPos);
  414. // Compile the initialization
  415. asQWORD constantValue;
  416. asCByteCode bc(engine);
  417. CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  418. bc.OptimizeLocally(tempVariableOffsets);
  419. byteCode->AddCode(&bc);
  420. script = origScript;
  421. #endif
  422. }
  423. }
  424. }
  425. // Entry
  426. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> &parameterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  427. {
  428. TimeIt("asCCompiler::CompileFunction");
  429. Reset(builder, script, outFunc);
  430. int buildErrors = builder->numErrors;
  431. int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
  432. //--------------------------------------------
  433. // Compile the statement block
  434. if( m_isConstructor )
  435. m_classDecl = classDecl;
  436. // We need to parse the statement block now
  437. asCScriptNode *blockBegin;
  438. // If the function signature was implicit, e.g. virtual property accessor or
  439. // lambda function, then the received node already is the statement block
  440. if( func->nodeType != snStatementBlock )
  441. blockBegin = func->lastChild;
  442. else
  443. blockBegin = func;
  444. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  445. // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated
  446. asCParser parser(builder);
  447. int r = parser.ParseStatementBlock(script, blockBegin);
  448. if( r < 0 ) return -1;
  449. asCScriptNode *block = parser.GetScriptNode();
  450. // Reserve a label for the cleanup code
  451. nextLabel++;
  452. bool hasReturn;
  453. asCByteCode bc(engine);
  454. LineInstr(&bc, blockBegin->tokenPos);
  455. CompileStatementBlock(block, false, &hasReturn, &bc);
  456. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  457. // Make sure there is a return in all paths (if not return type is void)
  458. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  459. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  460. {
  461. if( hasReturn == false )
  462. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  463. }
  464. //------------------------------------------------
  465. // Concatenate the bytecode
  466. // Insert a JitEntry at the start of the function for JIT compilers
  467. byteCode.InstrPTR(asBC_JitEntry, 0);
  468. if( outFunc->objectType )
  469. {
  470. if( m_isConstructor )
  471. {
  472. if( outFunc->objectType->derivedFrom )
  473. {
  474. // Call the base class' default constructor unless called manually in the code
  475. if( !m_isConstructorCalled )
  476. {
  477. if( outFunc->objectType->derivedFrom->beh.construct )
  478. {
  479. // Initialize members without explicit expression first
  480. CompileMemberInitialization(&byteCode, true);
  481. // Call base class' constructor
  482. asCByteCode tmpBC(engine);
  483. tmpBC.InstrSHORT(asBC_PSF, 0);
  484. tmpBC.Instr(asBC_RDSPtr);
  485. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  486. tmpBC.OptimizeLocally(tempVariableOffsets);
  487. byteCode.AddCode(&tmpBC);
  488. // Add the initialization of the members with explicit expressions
  489. CompileMemberInitialization(&byteCode, false);
  490. }
  491. else
  492. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  493. }
  494. else
  495. {
  496. // Only initialize members that don't have an explicit expression
  497. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  498. CompileMemberInitialization(&byteCode, true);
  499. }
  500. }
  501. else
  502. {
  503. // Add the initialization of the members
  504. CompileMemberInitialization(&byteCode, true);
  505. CompileMemberInitialization(&byteCode, false);
  506. }
  507. }
  508. }
  509. // Add the code for the statement block
  510. byteCode.AddCode(&bc);
  511. // Count total variable size
  512. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  513. outFunc->scriptData->variableSpace = varSize;
  514. // Deallocate all local variables
  515. int n;
  516. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  517. {
  518. sVariable *v = variables->variables[n];
  519. if( v->stackOffset > 0 )
  520. {
  521. // Call variables destructors
  522. if( v->name != "return" && v->name != "return address" )
  523. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  524. DeallocateVariable(v->stackOffset);
  525. }
  526. }
  527. // This is the label that return statements jump to
  528. // in order to exit the function
  529. byteCode.Label(0);
  530. // Call destructors for function parameters
  531. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  532. {
  533. sVariable *v = variables->variables[n];
  534. if( v->stackOffset <= 0 )
  535. {
  536. // Call variable destructors here, for variables not yet destroyed
  537. if( v->name != "return" && v->name != "return address" )
  538. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  539. }
  540. // Do not deallocate parameters
  541. }
  542. // Check if the number of labels in the functions isn't too many to be handled
  543. if( nextLabel >= (1<<15) )
  544. Error(TXT_TOO_MANY_JUMP_LABELS, func);
  545. // If there are compile errors, there is no reason to build the final code
  546. if( hasCompileErrors || builder->numErrors != buildErrors )
  547. return -1;
  548. // At this point there should be no variables allocated
  549. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  550. // Remove the variable scope
  551. RemoveVariableScope();
  552. byteCode.Ret(-stackPos);
  553. FinalizeFunction();
  554. #ifdef AS_DEBUG
  555. // DEBUG: output byte code
  556. if( outFunc->objectType )
  557. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  558. else
  559. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  560. #endif
  561. return 0;
  562. }
  563. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  564. {
  565. if( !type.IsObject() )
  566. return 0;
  567. // CallCopyConstructor should not be called for object handles.
  568. asASSERT( !type.IsObjectHandle() );
  569. asCArray<asSExprContext*> args;
  570. args.PushLast(arg);
  571. // The reference parameter must be pushed on the stack
  572. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  573. // Since we're calling the copy constructor, we have to trust the function to not do
  574. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  575. // copies of the argument in order to guarantee safety.
  576. if( type.GetObjectType()->flags & asOBJ_REF )
  577. {
  578. asSExprContext ctx(engine);
  579. int func = 0;
  580. asSTypeBehaviour *beh = type.GetBehaviour();
  581. if( beh ) func = beh->copyfactory;
  582. if( func > 0 )
  583. {
  584. if( !isGlobalVar )
  585. {
  586. // Call factory and store the handle in the given variable
  587. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  588. // Pop the reference left by the function call
  589. ctx.bc.Instr(asBC_PopPtr);
  590. }
  591. else
  592. {
  593. // Call factory
  594. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  595. // Store the returned handle in the global variable
  596. ctx.bc.Instr(asBC_RDSPtr);
  597. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  598. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  599. ctx.bc.Instr(asBC_PopPtr);
  600. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  601. }
  602. bc->AddCode(&ctx.bc);
  603. return 0;
  604. }
  605. }
  606. else
  607. {
  608. asSTypeBehaviour *beh = type.GetBehaviour();
  609. int func = beh ? beh->copyconstruct : 0;
  610. if( func > 0 )
  611. {
  612. // Push the address where the object will be stored on the stack, before the argument
  613. // TODO: When the context is serializable this probably has to be changed, since this
  614. // pointer can remain on the stack while the context is suspended. There is no
  615. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  616. asCByteCode tmp(engine);
  617. if( isGlobalVar )
  618. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  619. else if( isObjectOnHeap )
  620. tmp.InstrSHORT(asBC_PSF, (short)offset);
  621. tmp.AddCode(bc);
  622. bc->AddCode(&tmp);
  623. // When the object is allocated on the stack the object pointer
  624. // must be pushed on the stack after the arguments
  625. if( !isObjectOnHeap )
  626. {
  627. asASSERT( !isGlobalVar );
  628. bc->InstrSHORT(asBC_PSF, (short)offset);
  629. if( derefDest )
  630. {
  631. // The variable is a reference to the real location, so we need to dereference it
  632. bc->Instr(asBC_RDSPtr);
  633. }
  634. }
  635. asSExprContext ctx(engine);
  636. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  637. bc->AddCode(&ctx.bc);
  638. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  639. // Mark the object as initialized
  640. if( !isObjectOnHeap )
  641. bc->ObjInfo(offset, asOBJ_INIT);
  642. return 0;
  643. }
  644. }
  645. // Class has no copy constructor/factory.
  646. asCString str;
  647. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  648. Error(str, node);
  649. return -1;
  650. }
  651. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  652. {
  653. if( !type.IsObject() || type.IsObjectHandle() )
  654. return 0;
  655. if( type.GetObjectType()->flags & asOBJ_REF )
  656. {
  657. asSExprContext ctx(engine);
  658. ctx.exprNode = node;
  659. int func = 0;
  660. asSTypeBehaviour *beh = type.GetBehaviour();
  661. if( beh )
  662. {
  663. func = beh->factory;
  664. // If no trivial default factory is found, look for a factory where all params have default args
  665. if( func == 0 )
  666. {
  667. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  668. {
  669. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  670. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  671. f->defaultArgs[0] != 0 )
  672. {
  673. func = beh->factories[n];
  674. break;
  675. }
  676. }
  677. }
  678. }
  679. if( func > 0 )
  680. {
  681. asCArray<asSExprContext *> args;
  682. asCScriptFunction *f = engine->scriptFunctions[func];
  683. if( f->parameterTypes.GetLength() )
  684. {
  685. // Add the default values for arguments not explicitly supplied
  686. CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
  687. PrepareFunctionCall(func, &ctx.bc, args);
  688. MoveArgsToStack(func, &ctx.bc, args, false);
  689. }
  690. if( isVarGlobOrMem == 0 )
  691. {
  692. // Call factory and store the handle in the given variable
  693. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  694. // Pop the reference left by the function call
  695. ctx.bc.Instr(asBC_PopPtr);
  696. }
  697. else
  698. {
  699. // Call factory
  700. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  701. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  702. // instead of first storing it in a local variable and then copying it to the
  703. // destination.
  704. if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
  705. {
  706. // Only dereference the variable if not a scoped type
  707. ctx.bc.Instr(asBC_RDSPtr);
  708. }
  709. if( isVarGlobOrMem == 1 )
  710. {
  711. // Store the returned handle in the global variable
  712. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  713. }
  714. else
  715. {
  716. // Store the returned handle in the class member
  717. ctx.bc.InstrSHORT(asBC_PSF, 0);
  718. ctx.bc.Instr(asBC_RDSPtr);
  719. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  720. }
  721. if( type.GetObjectType()->flags & asOBJ_SCOPED )
  722. {
  723. // For scoped typed we must move the reference from the local
  724. // variable rather than copy it as there is no AddRef behaviour
  725. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  726. // Clear the local variable so the reference isn't released
  727. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  728. }
  729. else
  730. {
  731. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  732. }
  733. ctx.bc.Instr(asBC_PopPtr);
  734. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  735. }
  736. bc->AddCode(&ctx.bc);
  737. // Cleanup
  738. for( asUINT n = 0; n < args.GetLength(); n++ )
  739. if( args[n] )
  740. {
  741. asDELETE(args[n],asSExprContext);
  742. }
  743. return 0;
  744. }
  745. }
  746. else
  747. {
  748. asSExprContext ctx(engine);
  749. ctx.exprNode = node;
  750. asSTypeBehaviour *beh = type.GetBehaviour();
  751. int func = 0;
  752. if( beh )
  753. {
  754. func = beh->construct;
  755. // If no trivial default constructor is found, look for a constructor where all params have default args
  756. if( func == 0 )
  757. {
  758. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  759. {
  760. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  761. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  762. f->defaultArgs[0] != 0 )
  763. {
  764. func = beh->constructors[n];
  765. break;
  766. }
  767. }
  768. }
  769. }
  770. // Allocate and initialize with the default constructor
  771. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  772. {
  773. asCArray<asSExprContext *> args;
  774. asCScriptFunction *f = engine->scriptFunctions[func];
  775. if( f && f->parameterTypes.GetLength() )
  776. {
  777. // Add the default values for arguments not explicitly supplied
  778. CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
  779. PrepareFunctionCall(func, &ctx.bc, args);
  780. MoveArgsToStack(func, &ctx.bc, args, false);
  781. }
  782. if( !isObjectOnHeap )
  783. {
  784. if( isVarGlobOrMem == 0 )
  785. {
  786. // There is nothing to do if there is no function,
  787. // as the memory is already allocated on the stack
  788. if( func )
  789. {
  790. // Call the constructor as a normal function
  791. bc->InstrSHORT(asBC_PSF, (short)offset);
  792. if( derefDest )
  793. bc->Instr(asBC_RDSPtr);
  794. asSExprContext ctx(engine);
  795. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  796. bc->AddCode(&ctx.bc);
  797. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  798. // Mark the object as initialized
  799. bc->ObjInfo(offset, asOBJ_INIT);
  800. }
  801. }
  802. else if( isVarGlobOrMem == 2 )
  803. {
  804. // Only POD types can be allocated inline in script classes
  805. asASSERT( type.GetObjectType()->flags & asOBJ_POD );
  806. if( func )
  807. {
  808. // Call the constructor as a normal function
  809. bc->InstrSHORT(asBC_PSF, 0);
  810. bc->Instr(asBC_RDSPtr);
  811. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  812. asSExprContext ctx(engine);
  813. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  814. bc->AddCode(&ctx.bc);
  815. }
  816. }
  817. else
  818. {
  819. asASSERT( false );
  820. }
  821. }
  822. else
  823. {
  824. if( isVarGlobOrMem == 0 )
  825. bc->InstrSHORT(asBC_PSF, (short)offset);
  826. else if( isVarGlobOrMem == 1 )
  827. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  828. else
  829. {
  830. bc->InstrSHORT(asBC_PSF, 0);
  831. bc->Instr(asBC_RDSPtr);
  832. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  833. }
  834. if( (type.GetObjectType()->flags & asOBJ_TEMPLATE) )
  835. {
  836. asCScriptFunction *descr = engine->scriptFunctions[func];
  837. asASSERT( descr->funcType == asFUNC_SCRIPT );
  838. // Find the id of the real constructor and not the generated stub
  839. asUINT id = 0;
  840. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  841. while( funcBc )
  842. {
  843. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  844. {
  845. id = asBC_INTARG(funcBc);
  846. break;
  847. }
  848. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  849. }
  850. asASSERT( id );
  851. bc->InstrPTR(asBC_OBJTYPE, type.GetObjectType());
  852. bc->Alloc(asBC_ALLOC, type.GetObjectType(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  853. }
  854. else
  855. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  856. }
  857. // Cleanup
  858. for( asUINT n = 0; n < args.GetLength(); n++ )
  859. if( args[n] )
  860. {
  861. asDELETE(args[n],asSExprContext);
  862. }
  863. return 0;
  864. }
  865. }
  866. // Class has no default factory/constructor.
  867. asCString str;
  868. // TODO: funcdef: asCDataType should have a GetTypeName()
  869. if( type.GetFuncDef() )
  870. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  871. else
  872. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  873. Error(str, node);
  874. return -1;
  875. }
  876. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  877. {
  878. if( !type.IsReference() )
  879. {
  880. // Call destructor for the data type
  881. if( type.IsObject() )
  882. {
  883. // The null pointer doesn't need to be destroyed
  884. if( type.IsNullHandle() )
  885. return;
  886. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  887. if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN )
  888. return;
  889. if( isObjectOnHeap || type.IsObjectHandle() )
  890. {
  891. // Free the memory
  892. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  893. }
  894. else
  895. {
  896. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  897. if( type.GetBehaviour()->destruct )
  898. {
  899. // Call the destructor as a regular function
  900. asSExprContext ctx(engine);
  901. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  902. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  903. ctx.bc.OptimizeLocally(tempVariableOffsets);
  904. bc->AddCode(&ctx.bc);
  905. }
  906. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  907. // Mark the object as destroyed
  908. bc->ObjInfo(offset, asOBJ_UNINIT);
  909. }
  910. }
  911. }
  912. }
  913. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  914. {
  915. int r, c;
  916. script->ConvertPosToRowCol(pos, &r, &c);
  917. bc->Line(r, c, script->idx);
  918. }
  919. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  920. {
  921. *hasReturn = false;
  922. bool isFinished = false;
  923. bool hasUnreachableCode = false;
  924. bool hasReturnBefore = false;
  925. if( ownVariableScope )
  926. {
  927. bc->Block(true);
  928. AddVariableScope();
  929. }
  930. asCScriptNode *node = block->firstChild;
  931. while( node )
  932. {
  933. #ifdef AS_DEBUG
  934. // Keep the current line in a variable so it will be easier
  935. // to determine where in a script an assert is occurring.
  936. int currentLine = 0;
  937. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  938. #endif
  939. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  940. {
  941. // Empty statements don't count
  942. if( node->nodeType != snExpressionStatement || node->firstChild )
  943. {
  944. hasUnreachableCode = true;
  945. Warning(TXT_UNREACHABLE_CODE, node);
  946. }
  947. if( *hasReturn )
  948. hasReturnBefore = true;
  949. }
  950. if( node->nodeType == snBreak || node->nodeType == snContinue )
  951. isFinished = true;
  952. asCByteCode statement(engine);
  953. if( node->nodeType == snDeclaration )
  954. CompileDeclaration(node, &statement);
  955. else
  956. CompileStatement(node, hasReturn, &statement);
  957. // Ignore missing returns in unreachable code paths
  958. if( !(*hasReturn) && hasReturnBefore )
  959. *hasReturn = true;
  960. LineInstr(bc, node->tokenPos);
  961. bc->AddCode(&statement);
  962. if( !hasCompileErrors )
  963. {
  964. asASSERT( tempVariables.GetLength() == 0 );
  965. asASSERT( reservedVariables.GetLength() == 0 );
  966. }
  967. node = node->next;
  968. }
  969. if( ownVariableScope )
  970. {
  971. // Deallocate variables in this block, in reverse order
  972. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  973. {
  974. sVariable *v = variables->variables[n];
  975. // Call variable destructors here, for variables not yet destroyed
  976. // If the block is terminated with a break, continue, or
  977. // return the variables are already destroyed
  978. if( !isFinished && !*hasReturn )
  979. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  980. // Don't deallocate function parameters
  981. if( v->stackOffset > 0 )
  982. DeallocateVariable(v->stackOffset);
  983. }
  984. RemoveVariableScope();
  985. bc->Block(false);
  986. }
  987. }
  988. // Entry
  989. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  990. {
  991. Reset(builder, script, outFunc);
  992. m_globalVar = gvar;
  993. // Add a variable scope (even though variables can't be declared)
  994. AddVariableScope();
  995. gvar->isPureConstant = false;
  996. // Parse the initialization nodes
  997. asCParser parser(builder);
  998. if( node )
  999. {
  1000. int r = parser.ParseVarInit(script, node);
  1001. if( r < 0 )
  1002. return r;
  1003. node = parser.GetScriptNode();
  1004. }
  1005. asSExprContext compiledCtx(engine);
  1006. bool preCompiled = false;
  1007. if( gvar->datatype.IsAuto() )
  1008. preCompiled = CompileAutoType(gvar->datatype, compiledCtx, node, gvar->declaredAtNode);
  1009. if( gvar->property == 0 )
  1010. {
  1011. gvar->property = builder->module->AllocateGlobalProperty(gvar->name.AddressOf(), gvar->datatype, gvar->ns);
  1012. gvar->index = gvar->property->id;
  1013. }
  1014. // Compile the expression
  1015. asSExprContext ctx(engine);
  1016. asQWORD constantValue = 0;
  1017. if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1018. {
  1019. // Should the variable be marked as pure constant?
  1020. if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
  1021. {
  1022. gvar->isPureConstant = true;
  1023. gvar->constantValue = constantValue;
  1024. }
  1025. }
  1026. // Concatenate the bytecode
  1027. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1028. // Add information on the line number for the global variable
  1029. size_t pos = 0;
  1030. if( gvar->declaredAtNode )
  1031. pos = gvar->declaredAtNode->tokenPos;
  1032. else if( gvar->initializationNode )
  1033. pos = gvar->initializationNode->tokenPos;
  1034. LineInstr(&byteCode, pos);
  1035. // Reserve space for all local variables
  1036. outFunc->scriptData->variableSpace = varSize;
  1037. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1038. byteCode.AddCode(&ctx.bc);
  1039. // Deallocate variables in this block, in reverse order
  1040. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1041. {
  1042. sVariable *v = variables->variables[n];
  1043. // Call variable destructors here, for variables not yet destroyed
  1044. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1045. DeallocateVariable(v->stackOffset);
  1046. }
  1047. if( hasCompileErrors ) return -1;
  1048. // At this point there should be no variables allocated
  1049. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1050. // Remove the variable scope again
  1051. RemoveVariableScope();
  1052. byteCode.Ret(0);
  1053. FinalizeFunction();
  1054. #ifdef AS_DEBUG
  1055. // DEBUG: output byte code
  1056. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  1057. #endif
  1058. return 0;
  1059. }
  1060. void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
  1061. {
  1062. // Don't do anything if this is not a deferred global function
  1063. if( !ctx->IsGlobalFunc() )
  1064. return;
  1065. // Determine the namespace
  1066. asSNameSpace *ns = 0;
  1067. asCString name = "";
  1068. int pos = ctx->methodName.FindLast("::");
  1069. if( pos >= 0 )
  1070. {
  1071. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1072. // Cut off the ::
  1073. if( nsName.GetLength() > 2 )
  1074. nsName.SetLength(nsName.GetLength()-2);
  1075. ns = DetermineNameSpace(nsName);
  1076. name = ctx->methodName.SubString(pos+2);
  1077. }
  1078. else
  1079. {
  1080. DetermineNameSpace("");
  1081. name = ctx->methodName;
  1082. }
  1083. asCArray<int> funcs;
  1084. if( ns )
  1085. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1086. // CompileVariableAccess should guarantee that at least one function is exists
  1087. asASSERT( funcs.GetLength() > 0 );
  1088. if( funcs.GetLength() > 1 )
  1089. {
  1090. asCString str;
  1091. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1092. Error(str, node);
  1093. // Fall through so the compiler can continue as if only one function was matching
  1094. }
  1095. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1096. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1097. outFunc->IsShared() )
  1098. {
  1099. asCString msg;
  1100. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1101. Error(msg, node);
  1102. // Fall through so the compiler can continue anyway
  1103. }
  1104. // Push the function pointer on the stack
  1105. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1106. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  1107. ctx->type.dataType.MakeHandle(true);
  1108. ctx->type.isExplicitHandle = true;
  1109. ctx->methodName = "";
  1110. }
  1111. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination)
  1112. {
  1113. asASSERT( dt.GetObjectType() );
  1114. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1115. // Use copy constructor if available.
  1116. if( dt.GetObjectType()->beh.copyconstruct )
  1117. {
  1118. PrepareForAssignment(&dt, arg, node, true);
  1119. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1120. if( r < 0 && tempVariables.Exists(offset) )
  1121. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1122. }
  1123. else
  1124. {
  1125. // TODO: Need to reserve variables, as the default constructor may need
  1126. // to allocate temporary variables to compute default args
  1127. // Allocate and construct the temporary object before whatever is already in the bytecode
  1128. asCByteCode tmpBC(engine);
  1129. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1130. if( r < 0 )
  1131. {
  1132. if( tempVariables.Exists(offset) )
  1133. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1134. return;
  1135. }
  1136. tmpBC.AddCode(bc);
  1137. bc->AddCode(&tmpBC);
  1138. // Assign the evaluated expression to the temporary variable
  1139. PrepareForAssignment(&dt, arg, node, true);
  1140. bc->AddCode(&arg->bc);
  1141. // Call the opAssign method to assign the value to the temporary object
  1142. dt.MakeReference(isObjectOnHeap);
  1143. asCTypeInfo type;
  1144. type.Set(dt);
  1145. type.isTemporary = true;
  1146. type.stackOffset = (short)offset;
  1147. if( dt.IsObjectHandle() )
  1148. type.isExplicitHandle = true;
  1149. bc->InstrSHORT(asBC_PSF, (short)offset);
  1150. if( derefDestination )
  1151. bc->Instr(asBC_RDSPtr);
  1152. r = PerformAssignment(&type, &arg->type, bc, node);
  1153. if( r < 0 )
  1154. {
  1155. if( tempVariables.Exists(offset) )
  1156. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1157. return;
  1158. }
  1159. // Pop the reference that was pushed on the stack if the result is an object
  1160. if( type.dataType.IsObject() )
  1161. bc->Instr(asBC_PopPtr);
  1162. // If the assignment operator returned an object by value it will
  1163. // be in a temporary variable which we need to destroy now
  1164. if( type.isTemporary && type.stackOffset != (short)offset )
  1165. ReleaseTemporaryVariable(type.stackOffset, bc);
  1166. // Release the original value too in case it is a temporary
  1167. ReleaseTemporaryVariable(arg->type, bc);
  1168. }
  1169. }
  1170. int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1171. {
  1172. asCDataType param = *paramType;
  1173. if( paramType->GetTokenType() == ttQuestion )
  1174. {
  1175. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1176. DetermineSingleFunc(ctx, node);
  1177. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1178. param = ctx->type.dataType;
  1179. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1180. // Treat the void expression like a null handle when working with var types
  1181. if( ctx->IsVoidExpression() )
  1182. param = asCDataType::CreateNullHandle();
  1183. // If value assign is disabled for reference types, then make
  1184. // sure to always pass the handle to ? parameters
  1185. if( builder->engine->ep.disallowValueAssignForRefType &&
  1186. ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1187. {
  1188. param.MakeHandle(true);
  1189. }
  1190. param.MakeReference(paramType->IsReference());
  1191. param.MakeReadOnly(paramType->IsReadOnly());
  1192. }
  1193. else
  1194. param = *paramType;
  1195. asCDataType dt = param;
  1196. // Need to protect arguments by reference
  1197. if( isFunction && dt.IsReference() )
  1198. {
  1199. // Allocate a temporary variable of the same type as the argument
  1200. dt.MakeReference(false);
  1201. dt.MakeReadOnly(false);
  1202. int offset;
  1203. if( refType == 1 ) // &in
  1204. {
  1205. ProcessPropertyGetAccessor(ctx, node);
  1206. // Add the type id as hidden arg if the parameter is a ? type
  1207. if( paramType->GetTokenType() == ttQuestion )
  1208. {
  1209. asCByteCode tmpBC(engine);
  1210. // Place the type id on the stack as a hidden parameter
  1211. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1212. // Insert the code before the expression code
  1213. tmpBC.AddCode(&ctx->bc);
  1214. ctx->bc.AddCode(&tmpBC);
  1215. }
  1216. if( dt.IsPrimitive() )
  1217. {
  1218. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1219. // Even if the same variable is passed in another argument as non-const then there is no problem
  1220. IsVariableInitialized(&ctx->type, node);
  1221. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1222. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1223. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1224. ConvertToTempVariable(ctx);
  1225. PushVariableOnStack(ctx, true);
  1226. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1227. }
  1228. else if( ctx->type.dataType.IsNullHandle() )
  1229. {
  1230. // Make sure the argument type can support handles (or is itself a handle)
  1231. if( !dt.SupportHandles() && !dt.IsObjectHandle() )
  1232. {
  1233. asCString str;
  1234. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1235. Error(str, node);
  1236. ctx->type.Set(param);
  1237. return -1;
  1238. }
  1239. // Need to initialize a local temporary variable to
  1240. // represent the null handle when passed as reference
  1241. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1242. ctx->bc.Instr(asBC_PopPtr);
  1243. dt.MakeHandle(true);
  1244. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1245. // Push the reference to the variable on the stack
  1246. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1247. ctx->type.SetVariable(dt, offset, true);
  1248. }
  1249. else
  1250. {
  1251. IsVariableInitialized(&ctx->type, node);
  1252. if( !isMakingCopy )
  1253. {
  1254. // Even though the parameter expects a reference, it is only meant to be
  1255. // used as input value and doesn't have to refer to the actual object, so it
  1256. // is OK to do an implicit conversion.
  1257. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1258. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1259. {
  1260. asCString str;
  1261. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1262. Error(str, node);
  1263. ctx->type.Set(param);
  1264. return -1;
  1265. }
  1266. // The compiler must guarantee that the object stays alive during the execution
  1267. // of the function, and it must also guarantee that the value isn't modified by
  1268. // the function.
  1269. // If the argument is a temporary local variable then it is safe to be passed to
  1270. // the function as it is, since the local variable will stay alive, and since it
  1271. // is temporary there is no side effect if the function modifies it.
  1272. // If the parameter is read-only and therefor guaranteed not to be modified by the
  1273. // function, then it is enough that the variable is local to guarantee the lifetime.
  1274. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  1275. {
  1276. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1277. {
  1278. // If the object is a reference type (except scoped reference types), and the
  1279. // parameter is a const reference, then it is not necessary to make a copy of the
  1280. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1281. // Allocate a handle variable
  1282. dt.MakeHandle(true);
  1283. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1284. // Copy the handle
  1285. Dereference(ctx, true);
  1286. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1287. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1288. ctx->bc.Instr(asBC_PopPtr);
  1289. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1290. // The type should be set to the param type instead of dt to guarantee
  1291. // that the expression keeps the correct type for variable ? args. Otherwise
  1292. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1293. ctx->type.SetVariable(param, offset, true);
  1294. }
  1295. else
  1296. {
  1297. // Allocate and initialize a temporary local object
  1298. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1299. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1300. // Push the object pointer on the stack
  1301. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1302. if( dt.IsObject() && !dt.IsObjectHandle() )
  1303. ctx->bc.Instr(asBC_RDSPtr);
  1304. // Set the resulting type
  1305. ctx->type.Set(dt);
  1306. ctx->type.isTemporary = true;
  1307. ctx->type.stackOffset = short(offset);
  1308. if( dt.IsObjectHandle() )
  1309. ctx->type.isExplicitHandle = true;
  1310. ctx->type.dataType.MakeReference(false);
  1311. if( paramType->IsReadOnly() )
  1312. ctx->type.dataType.MakeReadOnly(true);
  1313. }
  1314. }
  1315. }
  1316. else
  1317. {
  1318. // We must guarantee that the address to the value is on the stack
  1319. if( ctx->type.dataType.IsObject() &&
  1320. !ctx->type.dataType.IsObjectHandle() &&
  1321. ctx->type.dataType.IsReference() )
  1322. Dereference(ctx, true);
  1323. }
  1324. }
  1325. }
  1326. else if( refType == 2 ) // &out
  1327. {
  1328. // Add the type id as hidden arg if the parameter is a ? type
  1329. if( paramType->GetTokenType() == ttQuestion )
  1330. {
  1331. asCByteCode tmpBC(engine);
  1332. // Place the type id on the stack as a hidden parameter
  1333. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1334. // Insert the code before the expression code
  1335. tmpBC.AddCode(&ctx->bc);
  1336. ctx->bc.AddCode(&tmpBC);
  1337. }
  1338. // If the expression is marked as clean, then it can be used directly
  1339. // without the need to allocate another temporary value as it is known
  1340. // that the argument has no other value than the default
  1341. if( ctx->isCleanArg )
  1342. {
  1343. // Must be a local variable
  1344. asASSERT( ctx->type.isVariable );
  1345. }
  1346. else
  1347. {
  1348. // Make sure the variable is not used in the expression
  1349. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1350. if( dt.IsPrimitive() )
  1351. {
  1352. ctx->type.SetVariable(dt, offset, true);
  1353. PushVariableOnStack(ctx, true);
  1354. }
  1355. else
  1356. {
  1357. // TODO: Need to reserve variables, as the default constructor may need
  1358. // to allocate temporary variables to compute default args
  1359. // Allocate and construct the temporary object
  1360. asCByteCode tmpBC(engine);
  1361. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1362. // Insert the code before the expression code
  1363. tmpBC.AddCode(&ctx->bc);
  1364. ctx->bc.AddCode(&tmpBC);
  1365. dt.MakeReference(!dt.IsObject() || dt.IsObjectHandle());
  1366. asCTypeInfo type;
  1367. type.Set(dt);
  1368. type.isTemporary = true;
  1369. type.stackOffset = (short)offset;
  1370. ctx->type = type;
  1371. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1372. if( dt.IsObject() && !dt.IsObjectHandle() )
  1373. ctx->bc.Instr(asBC_RDSPtr);
  1374. }
  1375. // After the function returns the temporary variable will
  1376. // be assigned to the expression, if it is a valid lvalue
  1377. }
  1378. }
  1379. else if( refType == asTM_INOUTREF )
  1380. {
  1381. ProcessPropertyGetAccessor(ctx, node);
  1382. // Add the type id as hidden arg if the parameter is a ? type
  1383. if( paramType->GetTokenType() == ttQuestion )
  1384. {
  1385. asCByteCode tmpBC(engine);
  1386. // Place the type id on the stack as a hidden parameter
  1387. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1388. // Insert the code before the expression code
  1389. tmpBC.AddCode(&ctx->bc);
  1390. ctx->bc.AddCode(&tmpBC);
  1391. }
  1392. // Literal constants cannot be passed to inout ref arguments
  1393. if( !ctx->type.isVariable && ctx->type.isConstant )
  1394. {
  1395. // Unless unsafe references are turned on and the reference is const
  1396. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1397. {
  1398. // Since the parameter is a const & make a copy.
  1399. ConvertToTempVariable(ctx);
  1400. ctx->type.dataType.MakeReadOnly(true);
  1401. }
  1402. else
  1403. {
  1404. Error(TXT_NOT_VALID_REFERENCE, node);
  1405. return -1;
  1406. }
  1407. }
  1408. // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
  1409. if( ctx->type.dataType.IsObject() && ctx->type.dataType.GetObjectType() != dt.GetObjectType() )
  1410. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1411. // Only objects that support object handles
  1412. // can be guaranteed to be safe. Local variables are
  1413. // already safe, so there is no need to add an extra
  1414. // references
  1415. if( !engine->ep.allowUnsafeReferences &&
  1416. !ctx->type.isVariable &&
  1417. ctx->type.dataType.IsObject() &&
  1418. !ctx->type.dataType.IsObjectHandle() &&
  1419. ((ctx->type.dataType.GetBehaviour()->addref &&
  1420. ctx->type.dataType.GetBehaviour()->release) ||
  1421. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1422. {
  1423. // Store a handle to the object as local variable
  1424. asSExprContext tmp(engine);
  1425. asCDataType dt = ctx->type.dataType;
  1426. dt.MakeHandle(true);
  1427. dt.MakeReference(false);
  1428. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1429. // Copy the handle
  1430. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1431. ctx->bc.Instr(asBC_RDSPtr);
  1432. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1433. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1434. ctx->bc.Instr(asBC_PopPtr);
  1435. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1436. dt.MakeHandle(false);
  1437. dt.MakeReference(true);
  1438. // Release previous temporary variable stored in the context (if any)
  1439. if( ctx->type.isTemporary )
  1440. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1441. ctx->type.SetVariable(dt, offset, true);
  1442. }
  1443. // Make sure the reference to the value is on the stack
  1444. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1445. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1446. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1447. Dereference(ctx, true);
  1448. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1449. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1450. else if( ctx->type.dataType.IsPrimitive() )
  1451. ctx->bc.Instr(asBC_PshRPtr);
  1452. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1453. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1454. }
  1455. }
  1456. else
  1457. {
  1458. ProcessPropertyGetAccessor(ctx, node);
  1459. if( dt.IsPrimitive() )
  1460. {
  1461. IsVariableInitialized(&ctx->type, node);
  1462. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1463. // Implicitly convert primitives to the parameter type
  1464. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1465. if( ctx->type.isVariable )
  1466. {
  1467. PushVariableOnStack(ctx, dt.IsReference());
  1468. }
  1469. else if( ctx->type.isConstant )
  1470. {
  1471. ConvertToVariable(ctx);
  1472. PushVariableOnStack(ctx, dt.IsReference());
  1473. }
  1474. }
  1475. else
  1476. {
  1477. IsVariableInitialized(&ctx->type, node);
  1478. // Implicitly convert primitives to the parameter type
  1479. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1480. // Was the conversion successful?
  1481. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1482. {
  1483. asCString str;
  1484. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1485. Error(str, node);
  1486. ctx->type.Set(dt);
  1487. return -1;
  1488. }
  1489. if( dt.IsObjectHandle() )
  1490. ctx->type.isExplicitHandle = true;
  1491. if( dt.IsObject() && !dt.IsNullHandle() )
  1492. {
  1493. if( !dt.IsReference() )
  1494. {
  1495. // Objects passed by value must be placed in temporary variables
  1496. // so that they are guaranteed to not be referenced anywhere else.
  1497. // The object must also be allocated on the heap, as the memory will
  1498. // be deleted by in as_callfunc_xxx.
  1499. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1500. // Local variables doesn't need to be copied into
  1501. // a temp if we're already compiling an assignment
  1502. if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
  1503. PrepareTemporaryObject(node, ctx, true);
  1504. // The implicit conversion shouldn't convert the object to
  1505. // non-reference yet. It will be dereferenced just before the call.
  1506. // Otherwise the object might be missed by the exception handler.
  1507. dt.MakeReference(true);
  1508. }
  1509. else
  1510. {
  1511. // An object passed by reference should place the pointer to
  1512. // the object on the stack.
  1513. dt.MakeReference(false);
  1514. }
  1515. }
  1516. }
  1517. }
  1518. // Don't put any pointer on the stack yet
  1519. if( param.IsReference() || (param.IsObject() && !param.IsNullHandle()) )
  1520. {
  1521. // &inout parameter may leave the reference on the stack already
  1522. if( refType != 3 )
  1523. {
  1524. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1525. if( ctx->type.isVariable || ctx->type.isTemporary )
  1526. {
  1527. ctx->bc.Instr(asBC_PopPtr);
  1528. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1529. ProcessDeferredParams(ctx);
  1530. }
  1531. }
  1532. }
  1533. return 0;
  1534. }
  1535. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1536. {
  1537. // When a match has been found, compile the final byte code using correct parameter types
  1538. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1539. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1540. // If the function being called is the opAssign or copy constructor for the same type
  1541. // as the argument, then we should avoid making temporary copy of the argument
  1542. bool makingCopy = false;
  1543. if( descr->parameterTypes.GetLength() == 1 &&
  1544. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1545. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1546. (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1547. makingCopy = true;
  1548. // Add code for arguments
  1549. asSExprContext e(engine);
  1550. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1551. {
  1552. // Make sure PrepareArgument doesn't use any variable that is already
  1553. // being used by any of the following argument expressions
  1554. int l = int(reservedVariables.GetLength());
  1555. for( int m = n-1; m >= 0; m-- )
  1556. args[m]->bc.GetVarsUsed(reservedVariables);
  1557. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1558. reservedVariables.SetLength(l);
  1559. }
  1560. bc->AddCode(&e.bc);
  1561. }
  1562. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1563. {
  1564. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1565. int offset = 0;
  1566. if( addOneToOffset )
  1567. offset += AS_PTR_SIZE;
  1568. // The address of where the return value should be stored is push on top of the arguments
  1569. if( descr->DoesReturnOnStack() )
  1570. offset += AS_PTR_SIZE;
  1571. #ifdef AS_DEBUG
  1572. // If the function being called is the opAssign or copy constructor for the same type
  1573. // as the argument, then we should avoid making temporary copy of the argument
  1574. bool makingCopy = false;
  1575. if( descr->parameterTypes.GetLength() == 1 &&
  1576. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1577. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1578. (descr->objectType == 0 && args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1579. makingCopy = true;
  1580. #endif
  1581. // Move the objects that are sent by value to the stack just before the call
  1582. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1583. {
  1584. if( descr->parameterTypes[n].IsReference() )
  1585. {
  1586. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1587. {
  1588. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1589. {
  1590. #ifdef AS_DEBUG
  1591. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1592. #endif
  1593. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1594. {
  1595. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1596. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1597. // as the value allocated on the stack is guaranteed to be safe
  1598. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1599. else
  1600. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1601. }
  1602. }
  1603. if( args[n]->type.dataType.IsObjectHandle() )
  1604. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1605. }
  1606. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1607. {
  1608. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1609. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1610. {
  1611. // Send the object as a reference to the object,
  1612. // and not to the variable holding the object
  1613. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1614. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1615. // as the value allocated on the stack is guaranteed to be safe
  1616. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1617. else
  1618. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1619. }
  1620. else
  1621. {
  1622. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1623. }
  1624. }
  1625. }
  1626. else if( descr->parameterTypes[n].IsObject() )
  1627. {
  1628. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1629. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1630. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1631. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1632. // The temporary variable must not be freed as it will no longer hold an object
  1633. DeallocateVariable(args[n]->type.stackOffset);
  1634. args[n]->type.isTemporary = false;
  1635. }
  1636. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1637. }
  1638. }
  1639. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1640. {
  1641. asASSERT(node->nodeType == snArgList);
  1642. // Count arguments
  1643. asCScriptNode *arg = node->firstChild;
  1644. int argCount = 0;
  1645. while( arg )
  1646. {
  1647. if( arg->nodeType != snNamedArgument )
  1648. argCount++;
  1649. arg = arg->next;
  1650. }
  1651. // Prepare the arrays
  1652. args.SetLength(argCount);
  1653. int n;
  1654. for( n = 0; n < argCount; n++ )
  1655. args[n] = 0;
  1656. n = argCount-1;
  1657. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1658. bool anyErrors = false, inPositionalArguments = false;
  1659. arg = node->lastChild;
  1660. while( arg )
  1661. {
  1662. asCScriptNode *asgNode = arg, *namedNode = 0;
  1663. if( asgNode->nodeType == snNamedArgument )
  1664. {
  1665. if( inPositionalArguments )
  1666. {
  1667. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1668. return -1;
  1669. }
  1670. asgNode = arg->firstChild->next;
  1671. namedNode = arg->firstChild;
  1672. asASSERT( namedNode->nodeType == snIdentifier );
  1673. }
  1674. else
  1675. inPositionalArguments = true;
  1676. asSExprContext expr(engine);
  1677. int r = CompileAssignment(asgNode, &expr);
  1678. if( r < 0 ) anyErrors = true;
  1679. asSExprContext *ctx = asNEW(asSExprContext)(engine);
  1680. if( ctx == 0 )
  1681. {
  1682. // Out of memory
  1683. return -1;
  1684. }
  1685. MergeExprBytecodeAndType(ctx, &expr);
  1686. if( inPositionalArguments )
  1687. {
  1688. args[n] = ctx;
  1689. n--;
  1690. }
  1691. else
  1692. {
  1693. asSNamedArgument namedArg;
  1694. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1695. namedArg.ctx = ctx;
  1696. // Error out when multiple arguments with the same name are passed
  1697. for( asUINT n = 0; n < namedArgs.GetLength(); ++n )
  1698. {
  1699. if( namedArgs[n].name == namedArg.name )
  1700. {
  1701. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1702. anyErrors = true;
  1703. break;
  1704. }
  1705. }
  1706. namedArgs.PushLast(namedArg);
  1707. }
  1708. arg = arg->prev;
  1709. }
  1710. return anyErrors ? -1 : 0;
  1711. }
  1712. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1713. {
  1714. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1715. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1716. return 0;
  1717. // Make sure to use the real function for virtual functions
  1718. if( func->funcType == asFUNC_VIRTUAL )
  1719. {
  1720. asASSERT( objectType );
  1721. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1722. }
  1723. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1724. bool anyErrors = false;
  1725. int prevReservedVars = reservedVariables.GetLength();
  1726. int explicitArgs = (int)args.GetLength();
  1727. for( int p = 0; p < explicitArgs; p++ )
  1728. args[p]->bc.GetVarsUsed(reservedVariables);
  1729. // Make space for all the new arguments
  1730. args.SetLength(func->parameterTypes.GetLength());
  1731. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1732. args[c] = 0;
  1733. // Add the named arguments to the argument list in the right position
  1734. if( namedArgs )
  1735. {
  1736. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1737. {
  1738. asSNamedArgument &named = (*namedArgs)[n];
  1739. named.ctx->bc.GetVarsUsed(reservedVariables);
  1740. // Find the right spot to put it in
  1741. asUINT index = asUINT(-1);
  1742. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1743. {
  1744. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1745. {
  1746. index = j;
  1747. break;
  1748. }
  1749. }
  1750. asASSERT( index < args.GetLength() );
  1751. args[index] = named.ctx;
  1752. named.ctx = 0;
  1753. }
  1754. }
  1755. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1756. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1757. {
  1758. if( args[n] != 0 ) continue;
  1759. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1760. // Parse the default arg string
  1761. asCParser parser(builder);
  1762. asCScriptCode code;
  1763. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1764. int r = parser.ParseExpression(&code);
  1765. if( r < 0 )
  1766. {
  1767. asCString msg;
  1768. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1769. Error(msg, node);
  1770. anyErrors = true;
  1771. continue;
  1772. }
  1773. asCScriptNode *arg = parser.GetScriptNode();
  1774. // Temporarily set the script code to the default arg expression
  1775. asCScriptCode *origScript = script;
  1776. script = &code;
  1777. // Don't allow the expression to access local variables
  1778. isCompilingDefaultArg = true;
  1779. // Temporarily set the namespace in the output function to the namespace of the called
  1780. // function so that the default arguments are evaluated in the correct namespace
  1781. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1782. outFunc->nameSpace = func->nameSpace;
  1783. asSExprContext expr(engine);
  1784. r = CompileExpression(arg, &expr);
  1785. // Restore the namespace
  1786. outFunc->nameSpace = origNameSpace;
  1787. // Don't allow address of class method
  1788. if( expr.methodName != "" )
  1789. {
  1790. // TODO: Improve error message
  1791. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1792. r = -1;
  1793. }
  1794. // Make sure the expression can be implicitly converted to the parameter type
  1795. if( r >= 0 )
  1796. {
  1797. asCArray<int> funcs;
  1798. funcs.PushLast(func->id);
  1799. asCArray<asSOverloadCandidate> matches;
  1800. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1801. {
  1802. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1803. r = -1;
  1804. }
  1805. }
  1806. isCompilingDefaultArg = false;
  1807. script = origScript;
  1808. if( r < 0 )
  1809. {
  1810. asCString msg;
  1811. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1812. Error(msg, node);
  1813. anyErrors = true;
  1814. continue;
  1815. }
  1816. args[n] = asNEW(asSExprContext)(engine);
  1817. if( args[n] == 0 )
  1818. {
  1819. // Out of memory
  1820. reservedVariables.SetLength(prevReservedVars);
  1821. return -1;
  1822. }
  1823. MergeExprBytecodeAndType(args[n], &expr);
  1824. }
  1825. reservedVariables.SetLength(prevReservedVars);
  1826. return anyErrors ? -1 : 0;
  1827. }
  1828. asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCArray<asSNamedArgument> *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1829. {
  1830. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1831. asUINT cost = 0;
  1832. asUINT n;
  1833. if( funcs.GetLength() > 0 )
  1834. {
  1835. // Check the number of parameters in the found functions
  1836. asUINT totalArgs = (asUINT)args.GetLength();
  1837. if( namedArgs != 0 )
  1838. totalArgs += (asUINT)namedArgs->GetLength();
  1839. for( n = 0; n < funcs.GetLength(); ++n )
  1840. {
  1841. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1842. if( desc->parameterTypes.GetLength() != totalArgs )
  1843. {
  1844. bool noMatch = true;
  1845. if( totalArgs < desc->parameterTypes.GetLength() )
  1846. {
  1847. // For virtual functions, the default args are defined in the real function of the object
  1848. if( desc->funcType == asFUNC_VIRTUAL )
  1849. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1850. // Count the number of default args
  1851. asUINT defaultArgs = 0;
  1852. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1853. if( desc->defaultArgs[d] )
  1854. defaultArgs++;
  1855. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1856. noMatch = false;
  1857. }
  1858. if( noMatch )
  1859. {
  1860. // remove it from the list
  1861. if( n == funcs.GetLength()-1 )
  1862. funcs.PopLast();
  1863. else
  1864. funcs[n] = funcs.PopLast();
  1865. n--;
  1866. }
  1867. }
  1868. }
  1869. // Match functions with the parameters, and discard those that do not match
  1870. asCArray<asSOverloadCandidate> matchingFuncs;
  1871. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1872. for ( n = 0; n < funcs.GetLength(); ++n )
  1873. {
  1874. matchingFuncs[n].funcId = funcs[n];
  1875. matchingFuncs[n].cost = 0;
  1876. }
  1877. // Match positionally passed arguments
  1878. for( n = 0; n < args.GetLength(); ++n )
  1879. {
  1880. asCArray<asSOverloadCandidate> tempFuncs;
  1881. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1882. // Intersect the found functions with the list of matching functions
  1883. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1884. {
  1885. asUINT c;
  1886. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1887. {
  1888. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1889. {
  1890. // Sum argument cost
  1891. matchingFuncs[f].cost += tempFuncs[c].cost;
  1892. break;
  1893. } // End if match
  1894. }
  1895. // Was the function a match?
  1896. if( c == tempFuncs.GetLength() )
  1897. {
  1898. // No, remove it from the list
  1899. if( f == matchingFuncs.GetLength()-1 )
  1900. matchingFuncs.PopLast();
  1901. else
  1902. matchingFuncs[f] = matchingFuncs.PopLast();
  1903. f--;
  1904. }
  1905. }
  1906. }
  1907. // Match named arguments
  1908. if( namedArgs != 0 )
  1909. {
  1910. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  1911. {
  1912. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  1913. if( desc->funcType == asFUNC_VIRTUAL )
  1914. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1915. // Match every named argument to an argument in the function
  1916. for( n = 0; n < namedArgs->GetLength(); ++n )
  1917. (*namedArgs)[n].match = asUINT(-1);
  1918. bool matchedAll = true;
  1919. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  1920. {
  1921. asUINT match = asUINT(-1);
  1922. for( n = 0; n < namedArgs->GetLength(); ++n )
  1923. {
  1924. asSNamedArgument &namedArg = (*namedArgs)[n];
  1925. if( desc->parameterNames[j] == namedArg.name )
  1926. {
  1927. namedArg.match = j;
  1928. match = n;
  1929. break;
  1930. }
  1931. }
  1932. // Check that every position is filled somehow
  1933. if( j >= args.GetLength() )
  1934. {
  1935. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  1936. {
  1937. // No argument was found for this, and there is no
  1938. // default, so it doesn't work.
  1939. matchedAll = false;
  1940. break;
  1941. }
  1942. }
  1943. else
  1944. {
  1945. if( match != asUINT(-1) )
  1946. {
  1947. // Can't name an argument that was already passed
  1948. matchedAll = false;
  1949. break;
  1950. }
  1951. }
  1952. }
  1953. // Check that every named argument was matched
  1954. if( matchedAll )
  1955. {
  1956. for( n = 0; n < namedArgs->GetLength(); ++n )
  1957. {
  1958. asSNamedArgument &named = (*namedArgs)[n];
  1959. if( named.match == asUINT(-1) )
  1960. {
  1961. matchedAll = false;
  1962. break;
  1963. }
  1964. // Add to the cost
  1965. asUINT cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  1966. if( cost == asUINT(-1) )
  1967. {
  1968. matchedAll = false;
  1969. break;
  1970. }
  1971. matchingFuncs[i].cost += cost;
  1972. }
  1973. }
  1974. if( !matchedAll )
  1975. {
  1976. // Remove the function, we didn't match all the arguments.
  1977. if( i == matchingFuncs.GetLength()-1 )
  1978. matchingFuncs.PopLast();
  1979. else
  1980. matchingFuncs[i] = matchingFuncs.PopLast();
  1981. i--;
  1982. }
  1983. }
  1984. }
  1985. // Select the overload(s) with the lowest overall cost
  1986. funcs.SetLength(0);
  1987. asUINT bestCost = asUINT(-1);
  1988. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  1989. {
  1990. cost = matchingFuncs[n].cost;
  1991. if( cost < bestCost )
  1992. {
  1993. funcs.SetLength(0);
  1994. bestCost = cost;
  1995. }
  1996. if( cost == bestCost )
  1997. funcs.PushLast( matchingFuncs[n].funcId );
  1998. }
  1999. // Cost returned is equivalent to the best cost discovered
  2000. cost = bestCost;
  2001. }
  2002. if( !isConstMethod )
  2003. FilterConst(funcs);
  2004. if( funcs.GetLength() != 1 && !silent )
  2005. {
  2006. // Build a readable string of the function with parameter types
  2007. bool attemptsPassingClassMethod = false;
  2008. asCString str;
  2009. if( scope != "" && scope != "::" )
  2010. str = scope + "::";
  2011. str += name;
  2012. str += "(";
  2013. for( n = 0; n < args.GetLength(); n++ )
  2014. {
  2015. if( n > 0 )
  2016. str += ", ";
  2017. if( args[n]->methodName != "" )
  2018. {
  2019. if( args[n]->IsClassMethod() )
  2020. {
  2021. attemptsPassingClassMethod = true;
  2022. str += args[n]->type.dataType.GetObjectType()->GetName();
  2023. str += "::";
  2024. }
  2025. str += args[n]->methodName;
  2026. }
  2027. else
  2028. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2029. }
  2030. if( namedArgs != 0 )
  2031. {
  2032. for( n = 0; n < namedArgs->GetLength(); n++ )
  2033. {
  2034. if( n > 0 || args.GetLength() )
  2035. str += ", ";
  2036. asSNamedArgument &named = (*namedArgs)[n];
  2037. str += named.name;
  2038. str += "=";
  2039. if( named.ctx->methodName != "" )
  2040. str += named.ctx->methodName;
  2041. else
  2042. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2043. }
  2044. }
  2045. str += ")";
  2046. if( isConstMethod )
  2047. str += " const";
  2048. if( objectType && scope == "" )
  2049. str = objectType->name + "::" + str;
  2050. if( funcs.GetLength() == 0 )
  2051. {
  2052. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2053. Error(str, node);
  2054. if( attemptsPassingClassMethod )
  2055. {
  2056. // Class methods must use delegate objects
  2057. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2058. }
  2059. else
  2060. {
  2061. // Print the list of candidates
  2062. if( origFuncs.GetLength() > 0 )
  2063. {
  2064. int r = 0, c = 0;
  2065. asASSERT( node );
  2066. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2067. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2068. PrintMatchingFuncs(origFuncs, node, objectType);
  2069. }
  2070. }
  2071. }
  2072. else
  2073. {
  2074. asASSERT( attemptsPassingClassMethod == false );
  2075. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2076. Error(str, node);
  2077. PrintMatchingFuncs(funcs, node, objectType);
  2078. }
  2079. }
  2080. return cost;
  2081. }
  2082. bool asCCompiler::CompileAutoType(asCDataType &type, asSExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2083. {
  2084. if( node && node->nodeType == snAssignment )
  2085. {
  2086. int r = CompileAssignment(node, &compiledCtx);
  2087. if( r >= 0 )
  2088. {
  2089. asCDataType newType = compiledCtx.type.dataType;
  2090. bool success = true;
  2091. // Handle const qualifier on auto
  2092. if( type.IsReadOnly() )
  2093. newType.MakeReadOnly(true);
  2094. else if( newType.IsPrimitive() )
  2095. newType.MakeReadOnly(false);
  2096. // Handle reference/value stuff
  2097. newType.MakeReference(false);
  2098. if( !newType.IsObjectHandle() )
  2099. {
  2100. // We got a value object or an object reference.
  2101. // Turn the variable into a handle if specified
  2102. // as auto@, otherwise make it a 'value'.
  2103. if( type.IsHandleToAuto() )
  2104. {
  2105. if( newType.MakeHandle(true) < 0 )
  2106. {
  2107. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2108. success = false;
  2109. }
  2110. }
  2111. }
  2112. if(success)
  2113. type = newType;
  2114. else
  2115. type = asCDataType::CreatePrimitive(ttInt, false);
  2116. return true;
  2117. }
  2118. return false;
  2119. }
  2120. else
  2121. {
  2122. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2123. type = asCDataType::CreatePrimitive(ttInt, false);
  2124. return false;
  2125. }
  2126. }
  2127. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2128. {
  2129. // Get the data type
  2130. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
  2131. // Declare all variables in this declaration
  2132. asCScriptNode *node = decl->firstChild->next;
  2133. while( node )
  2134. {
  2135. // If this is an auto type, we have to compile the assignment now to figure out the type
  2136. asSExprContext compiledCtx(engine);
  2137. bool preCompiled = false;
  2138. if( type.IsAuto() )
  2139. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2140. // Is the type allowed?
  2141. if( !type.CanBeInstantiated() )
  2142. {
  2143. asCString str;
  2144. if( type.IsAbstractClass() )
  2145. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2146. else if( type.IsInterface() )
  2147. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2148. else
  2149. // TODO: Improve error message to explain why
  2150. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2151. Error(str, node);
  2152. // Use int instead to avoid further problems
  2153. type = asCDataType::CreatePrimitive(ttInt, false);
  2154. }
  2155. // A shared object may not declare variables of non-shared types
  2156. if( outFunc->IsShared() )
  2157. {
  2158. asCObjectType *ot = type.GetObjectType();
  2159. if( ot && !ot->IsShared() )
  2160. {
  2161. asCString msg;
  2162. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2163. Error(msg, decl);
  2164. }
  2165. }
  2166. // Get the name of the identifier
  2167. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2168. // Verify that the name isn't used by a dynamic data type
  2169. // TODO: Must check against registered funcdefs too
  2170. if( engine->GetRegisteredObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2171. {
  2172. asCString str;
  2173. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2174. Error(str, node);
  2175. }
  2176. int offset = AllocateVariable(type, false);
  2177. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2178. {
  2179. // TODO: It might be an out-of-memory too
  2180. asCString str;
  2181. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2182. Error(str, node);
  2183. // Don't continue after this error, as it will just
  2184. // lead to more errors that are likely false
  2185. return;
  2186. }
  2187. else
  2188. {
  2189. // Warn if this variable hides another variable in a higher scope
  2190. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2191. {
  2192. asCString str;
  2193. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2194. Warning(str, node);
  2195. }
  2196. }
  2197. // Add marker that the variable has been declared
  2198. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2199. outFunc->AddVariable(name, type, offset);
  2200. // Keep the node for the variable decl
  2201. asCScriptNode *varNode = node;
  2202. node = node->next;
  2203. if( node == 0 || node->nodeType == snIdentifier )
  2204. {
  2205. // Initialize with default constructor
  2206. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2207. }
  2208. else
  2209. {
  2210. // Compile the initialization expression
  2211. asQWORD constantValue = 0;
  2212. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2213. {
  2214. // Check if the variable should be marked as pure constant
  2215. if( type.IsPrimitive() && type.IsReadOnly() )
  2216. {
  2217. sVariable *v = variables->GetVariable(name.AddressOf());
  2218. v->isPureConstant = true;
  2219. v->constantValue = constantValue;
  2220. }
  2221. }
  2222. node = node->next;
  2223. }
  2224. }
  2225. bc->OptimizeLocally(tempVariableOffsets);
  2226. }
  2227. // Returns true if the initialization expression is a constant expression
  2228. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled)
  2229. {
  2230. bool isConstantExpression = false;
  2231. if( node && node->nodeType == snArgList )
  2232. {
  2233. // Make sure it is an object and not a handle
  2234. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  2235. {
  2236. Error(TXT_MUST_BE_OBJECT, node);
  2237. }
  2238. else
  2239. {
  2240. // Compile the arguments
  2241. asCArray<asSExprContext *> args;
  2242. asCArray<asSNamedArgument> namedArgs;
  2243. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2244. {
  2245. // Find all constructors
  2246. asCArray<int> funcs;
  2247. asSTypeBehaviour *beh = type.GetBehaviour();
  2248. if( beh )
  2249. {
  2250. if( type.GetObjectType()->flags & asOBJ_REF )
  2251. funcs = beh->factories;
  2252. else
  2253. funcs = beh->constructors;
  2254. }
  2255. asCString str = type.Format(outFunc->nameSpace);
  2256. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2257. if( funcs.GetLength() == 1 )
  2258. {
  2259. // Add the default values for arguments not explicitly supplied
  2260. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType(), &namedArgs);
  2261. if( r == asSUCCESS )
  2262. {
  2263. asSExprContext ctx(engine);
  2264. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  2265. {
  2266. if( isVarGlobOrMem == 0 )
  2267. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2268. else
  2269. {
  2270. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2271. ctx.bc.Instr(asBC_RDSPtr);
  2272. if( isVarGlobOrMem == 1 )
  2273. {
  2274. // Store the returned handle in the global variable
  2275. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2276. }
  2277. else
  2278. {
  2279. // Store the returned handle in the member
  2280. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2281. ctx.bc.Instr(asBC_RDSPtr);
  2282. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2283. }
  2284. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  2285. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2286. }
  2287. // Pop the reference left by the function call
  2288. ctx.bc.Instr(asBC_PopPtr);
  2289. }
  2290. else
  2291. {
  2292. bool onHeap = false;
  2293. if( isVarGlobOrMem == 0 )
  2294. {
  2295. // When the object is allocated on the heap, the address where the
  2296. // reference will be stored must be pushed on the stack before the
  2297. // arguments. This reference on the stack is safe, even if the script
  2298. // is suspended during the evaluation of the arguments.
  2299. onHeap = IsVariableOnHeap(offset);
  2300. if( onHeap )
  2301. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2302. }
  2303. else if( isVarGlobOrMem == 1 )
  2304. {
  2305. // Push the address of the location where the variable will be stored on the stack.
  2306. // This reference is safe, because the addresses of the global variables cannot change.
  2307. onHeap = true;
  2308. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2309. }
  2310. else
  2311. {
  2312. // Value types may be allocated inline if they are POD types
  2313. onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
  2314. if( onHeap )
  2315. {
  2316. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2317. ctx.bc.Instr(asBC_RDSPtr);
  2318. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2319. }
  2320. }
  2321. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2322. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2323. // When the object is allocated on the stack, the address to the
  2324. // object is pushed on the stack after the arguments as the object pointer
  2325. if( !onHeap )
  2326. {
  2327. if( isVarGlobOrMem == 2 )
  2328. {
  2329. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2330. ctx.bc.Instr(asBC_RDSPtr);
  2331. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2332. }
  2333. else
  2334. {
  2335. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2336. }
  2337. }
  2338. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  2339. if( isVarGlobOrMem == 0 )
  2340. {
  2341. // Mark the object in the local variable as initialized
  2342. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2343. }
  2344. }
  2345. bc->AddCode(&ctx.bc);
  2346. }
  2347. }
  2348. }
  2349. // Cleanup
  2350. for( asUINT n = 0; n < args.GetLength(); n++ )
  2351. if( args[n] )
  2352. {
  2353. asDELETE(args[n],asSExprContext);
  2354. }
  2355. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2356. if( namedArgs[n].ctx )
  2357. {
  2358. asDELETE(namedArgs[n].ctx,asSExprContext);
  2359. }
  2360. }
  2361. }
  2362. else if( node && node->nodeType == snInitList )
  2363. {
  2364. asCTypeInfo ti;
  2365. ti.Set(type);
  2366. ti.isVariable = (isVarGlobOrMem == 0);
  2367. ti.isTemporary = false;
  2368. ti.stackOffset = (short)offset;
  2369. ti.isLValue = true;
  2370. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2371. }
  2372. else if( node && node->nodeType == snAssignment )
  2373. {
  2374. asSExprContext ctx(engine);
  2375. // Compile the expression
  2376. asSExprContext newExpr(engine);
  2377. asSExprContext* expr;
  2378. int r = 0;
  2379. if( preCompiled )
  2380. {
  2381. expr = preCompiled;
  2382. }
  2383. else
  2384. {
  2385. expr = &newExpr;
  2386. r = CompileAssignment(node, expr);
  2387. }
  2388. // Look for appropriate constructor
  2389. asCArray<int> funcs;
  2390. asCArray<asSExprContext *> args;
  2391. // Handles must use the handle assignment operation.
  2392. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2393. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2394. // Only do this if the expression is of the same type, as the expression is an assignment
  2395. // and an initialization constructor may not have the same meaning.
  2396. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2397. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2398. !(type.GetObjectType() && (type.GetObjectType()->GetFlags() & asOBJ_ASHANDLE)) &&
  2399. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2400. {
  2401. asSTypeBehaviour *beh = type.GetBehaviour();
  2402. if( beh )
  2403. {
  2404. if( type.GetObjectType()->flags & asOBJ_REF )
  2405. funcs = beh->factories;
  2406. else
  2407. funcs = beh->constructors;
  2408. }
  2409. asCString str = type.Format(outFunc->nameSpace);
  2410. args.PushLast(expr);
  2411. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2412. }
  2413. if( funcs.GetLength() == 1 )
  2414. {
  2415. // Use the constructor
  2416. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2417. // Add the default values for arguments not explicitly supplied
  2418. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType());
  2419. if( r == asSUCCESS )
  2420. {
  2421. asSExprContext ctx(engine);
  2422. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  2423. {
  2424. if( isVarGlobOrMem == 0 )
  2425. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2426. else
  2427. {
  2428. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2429. ctx.bc.Instr(asBC_RDSPtr);
  2430. if( isVarGlobOrMem == 1 )
  2431. {
  2432. // Store the returned handle in the global variable
  2433. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2434. }
  2435. else
  2436. {
  2437. // Store the returned handle in the member
  2438. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2439. ctx.bc.Instr(asBC_RDSPtr);
  2440. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2441. }
  2442. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  2443. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2444. }
  2445. // Pop the reference left by the function call
  2446. ctx.bc.Instr(asBC_PopPtr);
  2447. }
  2448. else
  2449. {
  2450. bool onHeap = false;
  2451. if( isVarGlobOrMem == 0 )
  2452. {
  2453. // When the object is allocated on the heap, the address where the
  2454. // reference will be stored must be pushed on the stack before the
  2455. // arguments. This reference on the stack is safe, even if the script
  2456. // is suspended during the evaluation of the arguments.
  2457. onHeap = IsVariableOnHeap(offset);
  2458. if( onHeap )
  2459. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2460. }
  2461. else if( isVarGlobOrMem == 1 )
  2462. {
  2463. // Push the address of the location where the variable will be stored on the stack.
  2464. // This reference is safe, because the addresses of the global variables cannot change.
  2465. onHeap = true;
  2466. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2467. }
  2468. else
  2469. {
  2470. // Value types may be allocated inline if they are POD types
  2471. onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
  2472. if( onHeap )
  2473. {
  2474. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2475. ctx.bc.Instr(asBC_RDSPtr);
  2476. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2477. }
  2478. }
  2479. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2480. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2481. // When the object is allocated on the stack, the address to the
  2482. // object is pushed on the stack after the arguments as the object pointer
  2483. if( !onHeap )
  2484. {
  2485. if( isVarGlobOrMem == 2 )
  2486. {
  2487. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2488. ctx.bc.Instr(asBC_RDSPtr);
  2489. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2490. }
  2491. else
  2492. {
  2493. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2494. }
  2495. }
  2496. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  2497. if( isVarGlobOrMem == 0 )
  2498. {
  2499. // Mark the object in the local variable as initialized
  2500. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2501. }
  2502. }
  2503. bc->AddCode(&ctx.bc);
  2504. }
  2505. }
  2506. else
  2507. {
  2508. // Call the default constructur, then call the assignment operator
  2509. // Call the default constructor here
  2510. if( isVarGlobOrMem == 0 )
  2511. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2512. else if( isVarGlobOrMem == 1 )
  2513. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2514. else if( isVarGlobOrMem == 2 )
  2515. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2516. if( r >= 0 )
  2517. {
  2518. if( type.IsPrimitive() )
  2519. {
  2520. if( type.IsReadOnly() && expr->type.isConstant )
  2521. {
  2522. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2523. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2524. isConstantExpression = true;
  2525. *constantValue = expr->type.qwordValue;
  2526. }
  2527. asSExprContext lctx(engine);
  2528. if( isVarGlobOrMem == 0 )
  2529. lctx.type.SetVariable(type, offset, false);
  2530. else if( isVarGlobOrMem == 1 )
  2531. {
  2532. lctx.type.Set(type);
  2533. lctx.type.dataType.MakeReference(true);
  2534. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2535. // we skip this as the bytecode won't be used anyway, only the constant value
  2536. if( offset >= 0 )
  2537. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2538. }
  2539. else
  2540. {
  2541. asASSERT( isVarGlobOrMem == 2 );
  2542. lctx.type.Set(type);
  2543. lctx.type.dataType.MakeReference(true);
  2544. // Load the reference of the primitive member into the register
  2545. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2546. lctx.bc.Instr(asBC_RDSPtr);
  2547. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2548. lctx.bc.Instr(asBC_PopRPtr);
  2549. }
  2550. lctx.type.dataType.MakeReadOnly(false);
  2551. lctx.type.isLValue = true;
  2552. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2553. ProcessDeferredParams(&ctx);
  2554. }
  2555. else
  2556. {
  2557. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2558. // just the copy constructor. Only if no appropriate constructor is
  2559. // available should the assignment operator be used.
  2560. asSExprContext lexpr(engine);
  2561. lexpr.type.Set(type);
  2562. if( isVarGlobOrMem == 0 )
  2563. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2564. else if( isVarGlobOrMem == 1 )
  2565. lexpr.type.dataType.MakeReference(true);
  2566. else if( isVarGlobOrMem == 2 )
  2567. {
  2568. if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) )
  2569. lexpr.type.dataType.MakeReference(true);
  2570. }
  2571. // Allow initialization of constant variables
  2572. lexpr.type.dataType.MakeReadOnly(false);
  2573. if( type.IsObjectHandle() )
  2574. lexpr.type.isExplicitHandle = true;
  2575. if( isVarGlobOrMem == 0 )
  2576. {
  2577. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2578. lexpr.type.stackOffset = (short)offset;
  2579. lexpr.type.isVariable = true;
  2580. }
  2581. else if( isVarGlobOrMem == 1 )
  2582. {
  2583. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2584. }
  2585. else
  2586. {
  2587. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2588. lexpr.bc.Instr(asBC_RDSPtr);
  2589. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2590. lexpr.type.stackOffset = -1;
  2591. }
  2592. lexpr.type.isLValue = true;
  2593. // If left expression resolves into a registered type
  2594. // check if the assignment operator is overloaded, and check
  2595. // the type of the right hand expression. If none is found
  2596. // the default action is a direct copy if it is the same type
  2597. // and a simple assignment.
  2598. bool assigned = false;
  2599. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2600. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  2601. {
  2602. bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType();
  2603. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, &ctx, useHndlAssign);
  2604. if( assigned )
  2605. {
  2606. // Pop the resulting value
  2607. if( !ctx.type.dataType.IsPrimitive() )
  2608. ctx.bc.Instr(asBC_PopPtr);
  2609. // Release the argument
  2610. ProcessDeferredParams(&ctx);
  2611. // Release temporary variable that may be allocated by the overloaded operator
  2612. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2613. }
  2614. }
  2615. if( !assigned )
  2616. {
  2617. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2618. // If the expression is constant and the variable also is constant
  2619. // then mark the variable as pure constant. This will allow the compiler
  2620. // to optimize expressions with this variable.
  2621. if( type.IsReadOnly() && expr->type.isConstant )
  2622. {
  2623. isConstantExpression = true;
  2624. *constantValue = expr->type.qwordValue;
  2625. }
  2626. // Add expression code to bytecode
  2627. MergeExprBytecode(&ctx, expr);
  2628. // Add byte code for storing value of expression in variable
  2629. ctx.bc.AddCode(&lexpr.bc);
  2630. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2631. // Release temporary variables used by expression
  2632. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2633. ctx.bc.Instr(asBC_PopPtr);
  2634. ProcessDeferredParams(&ctx);
  2635. }
  2636. }
  2637. }
  2638. bc->AddCode(&ctx.bc);
  2639. }
  2640. }
  2641. else
  2642. {
  2643. asASSERT( node == 0 );
  2644. // Call the default constructor here, as no explicit initialization is done
  2645. if( isVarGlobOrMem == 0 )
  2646. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2647. else if( isVarGlobOrMem == 1 )
  2648. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2649. else if( isVarGlobOrMem == 2 )
  2650. {
  2651. if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) )
  2652. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2653. else
  2654. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2655. }
  2656. }
  2657. return isConstantExpression;
  2658. }
  2659. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2660. {
  2661. // Check if the type supports initialization lists
  2662. if( var->dataType.GetObjectType() == 0 ||
  2663. var->dataType.GetBehaviour()->listFactory == 0 )
  2664. {
  2665. asCString str;
  2666. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2667. Error(str, node);
  2668. return;
  2669. }
  2670. // Construct the buffer with the elements
  2671. // Find the list factory
  2672. int funcId = var->dataType.GetBehaviour()->listFactory;
  2673. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2674. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2675. // for small buffers so that the dynamic allocation is skipped
  2676. // Create a new special object type for the lists. Both asCRestore and the
  2677. // context exception handler will need this to know how to parse the buffer.
  2678. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2679. // Allocate a temporary variable to hold the pointer to the buffer
  2680. int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true);
  2681. asUINT bufferSize = 0;
  2682. // Evaluate all elements of the list
  2683. asSExprContext valueExpr(engine);
  2684. asCScriptNode *el = node;
  2685. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2686. int elementsInSubList = -1;
  2687. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2688. asASSERT( r || patternNode == 0 );
  2689. UNUSED_VAR(r);
  2690. // After all values have been evaluated we know the final size of the buffer
  2691. asSExprContext allocExpr(engine);
  2692. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2693. // Merge the bytecode into the final sequence
  2694. bc->AddCode(&allocExpr.bc);
  2695. bc->AddCode(&valueExpr.bc);
  2696. // The object itself is the last to be created and will receive the pointer to the buffer
  2697. asCArray<asSExprContext *> args;
  2698. asSExprContext arg1(engine);
  2699. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2700. arg1.type.dataType.MakeReference(true);
  2701. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2702. args.PushLast(&arg1);
  2703. asSExprContext ctx(engine);
  2704. if( var->isVariable )
  2705. {
  2706. asASSERT( isVarGlobOrMem == 0 );
  2707. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2708. {
  2709. ctx.bc.AddCode(&arg1.bc);
  2710. // Call factory and store the handle in the given variable
  2711. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2712. ctx.bc.Instr(asBC_PopPtr);
  2713. }
  2714. else
  2715. {
  2716. // Call the constructor
  2717. // When the object is allocated on the heap, the address where the
  2718. // reference will be stored must be pushed on the stack before the
  2719. // arguments. This reference on the stack is safe, even if the script
  2720. // is suspended during the evaluation of the arguments.
  2721. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2722. if( onHeap )
  2723. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2724. ctx.bc.AddCode(&arg1.bc);
  2725. // When the object is allocated on the stack, the address to the
  2726. // object is pushed on the stack after the arguments as the object pointer
  2727. if( !onHeap )
  2728. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2729. PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
  2730. // Mark the object in the local variable as initialized
  2731. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2732. }
  2733. }
  2734. else
  2735. {
  2736. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2737. {
  2738. ctx.bc.AddCode(&arg1.bc);
  2739. PerformFunctionCall(funcId, &ctx, false, &args);
  2740. ctx.bc.Instr(asBC_RDSPtr);
  2741. if( isVarGlobOrMem == 1 )
  2742. {
  2743. // Store the returned handle in the global variable
  2744. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2745. }
  2746. else
  2747. {
  2748. // Store the returned handle in the member
  2749. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2750. ctx.bc.Instr(asBC_RDSPtr);
  2751. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2752. }
  2753. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  2754. ctx.bc.Instr(asBC_PopPtr);
  2755. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2756. }
  2757. else
  2758. {
  2759. bool onHeap = true;
  2760. // Put the address where the object pointer will be placed on the stack
  2761. if( isVarGlobOrMem == 1 )
  2762. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2763. else
  2764. {
  2765. onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->flags & asOBJ_REF);
  2766. if( onHeap )
  2767. {
  2768. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2769. ctx.bc.Instr(asBC_RDSPtr);
  2770. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2771. }
  2772. }
  2773. // Add the address of the list buffer as the argument
  2774. ctx.bc.AddCode(&arg1.bc);
  2775. if( !onHeap )
  2776. {
  2777. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2778. ctx.bc.Instr(asBC_RDSPtr);
  2779. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2780. }
  2781. // Call the ALLOC instruction to allocate memory and invoke constructor
  2782. PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
  2783. }
  2784. }
  2785. bc->AddCode(&ctx.bc);
  2786. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2787. // each element in the buffer so there is no need to do this manually
  2788. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  2789. ReleaseTemporaryVariable(bufferVar, bc);
  2790. }
  2791. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList)
  2792. {
  2793. if( patternNode->type == asLPT_START )
  2794. {
  2795. if( valueNode == 0 || valueNode->nodeType != snInitList )
  2796. {
  2797. Error(TXT_EXPECTED_LIST, valueNode);
  2798. return -1;
  2799. }
  2800. // Compile all values until asLPT_END
  2801. patternNode = patternNode->next;
  2802. asCScriptNode *node = valueNode->firstChild;
  2803. while( patternNode->type != asLPT_END )
  2804. {
  2805. // Check for missing value here, else the error reporting will not have a source position to report the error for
  2806. if( node == 0 && patternNode->type == asLPT_TYPE )
  2807. {
  2808. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  2809. return -1;
  2810. }
  2811. asCScriptNode *errNode = node;
  2812. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode, elementsInSubList);
  2813. if( r < 0 ) return r;
  2814. if( r == 1 )
  2815. {
  2816. asASSERT( engine->ep.disallowEmptyListElements );
  2817. // Empty elements in the middle are not allowed
  2818. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  2819. }
  2820. asASSERT( patternNode );
  2821. }
  2822. if( node )
  2823. {
  2824. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  2825. return -1;
  2826. }
  2827. // Move to the next node
  2828. valueNode = valueNode->next;
  2829. patternNode = patternNode->next;
  2830. }
  2831. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  2832. {
  2833. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  2834. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  2835. asEListPatternNodeType repeatType = patternNode->type;
  2836. asCScriptNode *firstValue = valueNode;
  2837. // The following values will be repeated N times
  2838. patternNode = patternNode->next;
  2839. // Keep track of the patternNode so it can be reset
  2840. asSListPatternNode *nextNode = patternNode;
  2841. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  2842. if( bufferSize & 0x3 )
  2843. bufferSize += 4 - (bufferSize & 0x3);
  2844. // The first dword will hold the number of elements in the list
  2845. asDWORD currSize = bufferSize;
  2846. bufferSize += 4;
  2847. asUINT countElements = 0;
  2848. int elementsInSubSubList = -1;
  2849. asSExprContext ctx(engine);
  2850. while( valueNode )
  2851. {
  2852. patternNode = nextNode;
  2853. asCScriptNode *errNode = valueNode;
  2854. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  2855. if( r < 0 ) return r;
  2856. if( r == 0 )
  2857. countElements++;
  2858. else
  2859. {
  2860. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  2861. if( valueNode )
  2862. {
  2863. // Empty elements in the middle are not allowed
  2864. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  2865. }
  2866. }
  2867. }
  2868. if( countElements == 0 )
  2869. {
  2870. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  2871. patternNode = nextNode;
  2872. if( patternNode->type == asLPT_TYPE )
  2873. patternNode = patternNode->next;
  2874. else if( patternNode->type == asLPT_START )
  2875. {
  2876. int subCount = 1;
  2877. do
  2878. {
  2879. patternNode = patternNode->next;
  2880. if( patternNode->type == asLPT_START )
  2881. subCount++;
  2882. else if( patternNode->type == asLPT_END )
  2883. subCount--;
  2884. } while( subCount > 0 );
  2885. patternNode = patternNode->next;
  2886. }
  2887. }
  2888. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  2889. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  2890. {
  2891. if( countElements < asUINT(elementsInSubList) )
  2892. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  2893. else
  2894. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  2895. return -1;
  2896. }
  2897. else
  2898. {
  2899. // Return to caller the amount of elments in this sublist
  2900. elementsInSubList = countElements;
  2901. }
  2902. // The first dword in the buffer will hold the number of elements
  2903. byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  2904. // Add the values
  2905. byteCode.AddCode(&ctx.bc);
  2906. }
  2907. else if( patternNode->type == asLPT_TYPE )
  2908. {
  2909. bool isEmpty = false;
  2910. // Determine the size of the element
  2911. asUINT size = 0;
  2912. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  2913. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  2914. {
  2915. asSExprContext lctx(engine);
  2916. asSExprContext rctx(engine);
  2917. if( valueNode->nodeType == snAssignment )
  2918. {
  2919. // Compile the assignment expression
  2920. CompileAssignment(valueNode, &rctx);
  2921. if( dt.GetTokenType() == ttQuestion )
  2922. {
  2923. // We now know the type
  2924. dt = rctx.type.dataType;
  2925. dt.MakeReadOnly(false);
  2926. dt.MakeReference(false);
  2927. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2928. if( bufferSize & 0x3 )
  2929. bufferSize += 4 - (bufferSize & 0x3);
  2930. // Place the type id in the buffer
  2931. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  2932. bufferSize += 4;
  2933. }
  2934. }
  2935. else if( valueNode->nodeType == snInitList )
  2936. {
  2937. if( dt.GetTokenType() == ttQuestion )
  2938. {
  2939. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  2940. asCString str;
  2941. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  2942. Error(str.AddressOf(), valueNode);
  2943. rctx.type.SetDummy();
  2944. dt = rctx.type.dataType;
  2945. }
  2946. else
  2947. {
  2948. // Allocate a temporary variable that will be initialized with the list
  2949. int offset = AllocateVariable(dt, true);
  2950. rctx.type.Set(dt);
  2951. rctx.type.isVariable = true;
  2952. rctx.type.isTemporary = true;
  2953. rctx.type.stackOffset = (short)offset;
  2954. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  2955. // Put the object on the stack
  2956. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  2957. // It is a reference that we place on the stack
  2958. rctx.type.dataType.MakeReference(true);
  2959. }
  2960. }
  2961. // Determine size of the element
  2962. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2963. size = dt.GetSizeInMemoryBytes();
  2964. else
  2965. size = AS_PTR_SIZE*4;
  2966. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2967. if( size >= 4 && (bufferSize & 0x3) )
  2968. bufferSize += 4 - (bufferSize & 0x3);
  2969. // Compile the lvalue
  2970. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2971. lctx.type.Set(dt);
  2972. lctx.type.isLValue = true;
  2973. if( dt.IsPrimitive() )
  2974. {
  2975. lctx.bc.Instr(asBC_PopRPtr);
  2976. lctx.type.dataType.MakeReference(true);
  2977. }
  2978. else if( dt.IsObjectHandle() ||
  2979. dt.GetObjectType()->flags & asOBJ_REF )
  2980. {
  2981. lctx.type.isExplicitHandle = true;
  2982. lctx.type.dataType.MakeReference(true);
  2983. }
  2984. else
  2985. {
  2986. asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE );
  2987. // Make sure the object has been constructed before the assignment
  2988. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  2989. asSTypeBehaviour *beh = dt.GetBehaviour();
  2990. int func = 0;
  2991. if( beh ) func = beh->construct;
  2992. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2993. {
  2994. asCString str;
  2995. // TODO: funcdef: asCDataType should have a GetTypeName()
  2996. if( dt.GetFuncDef() )
  2997. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2998. else
  2999. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  3000. Error(str, valueNode);
  3001. }
  3002. else if( func )
  3003. {
  3004. // Call the constructor as a normal function
  3005. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3006. asSExprContext ctx(engine);
  3007. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  3008. byteCode.AddCode(&ctx.bc);
  3009. }
  3010. }
  3011. if( lctx.type.dataType.IsNullHandle() )
  3012. {
  3013. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3014. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3015. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3016. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3017. }
  3018. else
  3019. {
  3020. asSExprContext ctx(engine);
  3021. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3022. if( !lctx.type.dataType.IsPrimitive() )
  3023. ctx.bc.Instr(asBC_PopPtr);
  3024. // Release temporary variables used by expression
  3025. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3026. ProcessDeferredParams(&ctx);
  3027. byteCode.AddCode(&ctx.bc);
  3028. }
  3029. }
  3030. else
  3031. {
  3032. if( builder->engine->ep.disallowEmptyListElements )
  3033. {
  3034. // Empty elements are not allowed, except if it is the last in the list
  3035. isEmpty = true;
  3036. }
  3037. else
  3038. {
  3039. // There is no specific value so we need to fill it with a default value
  3040. if( dt.GetTokenType() == ttQuestion )
  3041. {
  3042. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3043. if( bufferSize & 0x3 )
  3044. bufferSize += 4 - (bufferSize & 0x3);
  3045. // Place the type id for a null handle in the buffer
  3046. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3047. bufferSize += 4;
  3048. dt = asCDataType::CreateNullHandle();
  3049. // No need to initialize the handle as the buffer is already initialized with zeroes
  3050. }
  3051. else if( dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_VALUE )
  3052. {
  3053. // For value types with default constructor we need to call the constructor
  3054. asSTypeBehaviour *beh = dt.GetBehaviour();
  3055. int func = 0;
  3056. if( beh ) func = beh->construct;
  3057. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  3058. {
  3059. asCString str;
  3060. // TODO: funcdef: asCDataType should have a GetTypeName()
  3061. if( dt.GetFuncDef() )
  3062. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  3063. else
  3064. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  3065. Error(str, valueNode);
  3066. }
  3067. else if( func )
  3068. {
  3069. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3070. if( bufferSize & 0x3 )
  3071. bufferSize += 4 - (bufferSize & 0x3);
  3072. // Call the constructor as a normal function
  3073. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3074. asSExprContext ctx(engine);
  3075. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  3076. byteCode.AddCode(&ctx.bc);
  3077. }
  3078. }
  3079. else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF )
  3080. {
  3081. // For ref types (not handles) we need to call the default factory
  3082. asSTypeBehaviour *beh = dt.GetBehaviour();
  3083. int func = 0;
  3084. if( beh ) func = beh->factory;
  3085. if( func == 0 )
  3086. {
  3087. asCString str;
  3088. // TODO: funcdef: asCDataType should have a GetTypeName()
  3089. if( dt.GetFuncDef() )
  3090. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  3091. else
  3092. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  3093. Error(str, valueNode);
  3094. }
  3095. else if( func )
  3096. {
  3097. asSExprContext rctx(engine);
  3098. PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType());
  3099. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3100. if( bufferSize & 0x3 )
  3101. bufferSize += 4 - (bufferSize & 0x3);
  3102. asSExprContext lctx(engine);
  3103. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3104. lctx.type.Set(dt);
  3105. lctx.type.isLValue = true;
  3106. lctx.type.isExplicitHandle = true;
  3107. lctx.type.dataType.MakeReference(true);
  3108. asSExprContext ctx(engine);
  3109. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3110. if( !lctx.type.dataType.IsPrimitive() )
  3111. ctx.bc.Instr(asBC_PopPtr);
  3112. // Release temporary variables used by expression
  3113. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3114. ProcessDeferredParams(&ctx);
  3115. byteCode.AddCode(&ctx.bc);
  3116. }
  3117. }
  3118. }
  3119. }
  3120. if( !isEmpty )
  3121. {
  3122. // Determine size of the element
  3123. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  3124. size = dt.GetSizeInMemoryBytes();
  3125. else
  3126. size = AS_PTR_SIZE*4;
  3127. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3128. bufferSize += size;
  3129. }
  3130. // Move to the next element
  3131. patternNode = patternNode->next;
  3132. valueNode = valueNode->next;
  3133. if( isEmpty )
  3134. {
  3135. // The caller will determine if the empty element should be ignored or not
  3136. return 1;
  3137. }
  3138. }
  3139. else
  3140. asASSERT( false );
  3141. return 0;
  3142. }
  3143. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3144. {
  3145. // Don't clear the hasReturn flag if this is an empty statement
  3146. // to avoid false errors of 'not all paths return'
  3147. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3148. *hasReturn = false;
  3149. if( statement->nodeType == snStatementBlock )
  3150. CompileStatementBlock(statement, true, hasReturn, bc);
  3151. else if( statement->nodeType == snIf )
  3152. CompileIfStatement(statement, hasReturn, bc);
  3153. else if( statement->nodeType == snFor )
  3154. CompileForStatement(statement, bc);
  3155. else if( statement->nodeType == snWhile )
  3156. CompileWhileStatement(statement, bc);
  3157. else if( statement->nodeType == snDoWhile )
  3158. CompileDoWhileStatement(statement, bc);
  3159. else if( statement->nodeType == snExpressionStatement )
  3160. CompileExpressionStatement(statement, bc);
  3161. else if( statement->nodeType == snBreak )
  3162. CompileBreakStatement(statement, bc);
  3163. else if( statement->nodeType == snContinue )
  3164. CompileContinueStatement(statement, bc);
  3165. else if( statement->nodeType == snSwitch )
  3166. CompileSwitchStatement(statement, hasReturn, bc);
  3167. else if( statement->nodeType == snReturn )
  3168. {
  3169. CompileReturnStatement(statement, bc);
  3170. *hasReturn = true;
  3171. }
  3172. }
  3173. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3174. {
  3175. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3176. // Reserve label for break statements
  3177. int breakLabel = nextLabel++;
  3178. breakLabels.PushLast(breakLabel);
  3179. // Add a variable scope that will be used by CompileBreak
  3180. // to know where to stop deallocating variables
  3181. AddVariableScope(true, false);
  3182. //---------------------------
  3183. // Compile the switch expression
  3184. //-------------------------------
  3185. // Compile the switch expression
  3186. asSExprContext expr(engine);
  3187. CompileAssignment(snode->firstChild, &expr);
  3188. // Verify that the expression is a primitive type
  3189. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3190. {
  3191. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3192. return;
  3193. }
  3194. ProcessPropertyGetAccessor(&expr, snode);
  3195. // TODO: Need to support 64bit integers
  3196. // Convert the expression to a 32bit variable
  3197. asCDataType to;
  3198. if( expr.type.dataType.IsIntegerType() )
  3199. to.SetTokenType(ttInt);
  3200. else if( expr.type.dataType.IsUnsignedType() )
  3201. to.SetTokenType(ttUInt);
  3202. // Make sure the value is in a variable
  3203. if( expr.type.dataType.IsReference() )
  3204. ConvertToVariable(&expr);
  3205. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3206. ConvertToVariable(&expr);
  3207. int offset = expr.type.stackOffset;
  3208. ProcessDeferredParams(&expr);
  3209. //-------------------------------
  3210. // Determine case values and labels
  3211. //--------------------------------
  3212. // Remember the first label so that we can later pass the
  3213. // correct label to each CompileCase()
  3214. int firstCaseLabel = nextLabel;
  3215. int defaultLabel = 0;
  3216. asCArray<int> caseValues;
  3217. asCArray<int> caseLabels;
  3218. // Compile all case comparisons and make them jump to the right label
  3219. asCScriptNode *cnode = snode->firstChild->next;
  3220. while( cnode )
  3221. {
  3222. // Each case should have a constant expression
  3223. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3224. {
  3225. // Compile expression
  3226. asSExprContext c(engine);
  3227. CompileExpression(cnode->firstChild, &c);
  3228. // Verify that the result is a constant
  3229. if( !c.type.isConstant )
  3230. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3231. // Verify that the result is an integral number
  3232. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
  3233. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3234. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3235. // Has this case been declared already?
  3236. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  3237. {
  3238. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3239. }
  3240. // TODO: Optimize: We can insert the numbers sorted already
  3241. // Store constant for later use
  3242. caseValues.PushLast(c.type.intValue);
  3243. // Reserve label for this case
  3244. caseLabels.PushLast(nextLabel++);
  3245. }
  3246. else
  3247. {
  3248. // TODO: It shouldn't be necessary for the default case to be the last one.
  3249. // Is default the last case?
  3250. if( cnode->next )
  3251. {
  3252. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3253. break;
  3254. }
  3255. // Reserve label for this case
  3256. defaultLabel = nextLabel++;
  3257. }
  3258. cnode = cnode->next;
  3259. }
  3260. // check for empty switch
  3261. if (caseValues.GetLength() == 0)
  3262. {
  3263. Error(TXT_EMPTY_SWITCH, snode);
  3264. return;
  3265. }
  3266. if( defaultLabel == 0 )
  3267. defaultLabel = breakLabel;
  3268. //---------------------------------
  3269. // Output the optimized case comparisons
  3270. // with jumps to the case code
  3271. //------------------------------------
  3272. // Sort the case values by increasing value. Do the sort together with the labels
  3273. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3274. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3275. {
  3276. for( int bck = fwd - 1; bck >= 0; bck-- )
  3277. {
  3278. int bckp = bck + 1;
  3279. if( caseValues[bck] > caseValues[bckp] )
  3280. {
  3281. // Swap the values in both arrays
  3282. int swap = caseValues[bckp];
  3283. caseValues[bckp] = caseValues[bck];
  3284. caseValues[bck] = swap;
  3285. swap = caseLabels[bckp];
  3286. caseLabels[bckp] = caseLabels[bck];
  3287. caseLabels[bck] = swap;
  3288. }
  3289. else
  3290. break;
  3291. }
  3292. }
  3293. // Find ranges of consecutive numbers
  3294. asCArray<int> ranges;
  3295. ranges.PushLast(0);
  3296. asUINT n;
  3297. for( n = 1; n < caseValues.GetLength(); ++n )
  3298. {
  3299. // We can join numbers that are less than 5 numbers
  3300. // apart since the output code will still be smaller
  3301. if( caseValues[n] > caseValues[n-1] + 5 )
  3302. ranges.PushLast(n);
  3303. }
  3304. // If the value is larger than the largest case value, jump to default
  3305. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3306. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3307. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3308. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3309. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3310. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3311. // binary search instead of a linear search through the ranges
  3312. // For each range
  3313. int range;
  3314. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3315. {
  3316. // Find the largest value in this range
  3317. int maxRange = caseValues[ranges[range]];
  3318. int index = ranges[range];
  3319. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3320. maxRange = caseValues[index];
  3321. // If there are only 2 numbers then it is better to compare them directly
  3322. if( index - ranges[range] > 2 )
  3323. {
  3324. // If the value is smaller than the smallest case value in the range, jump to default
  3325. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3326. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3327. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3328. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3329. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3330. int nextRangeLabel = nextLabel++;
  3331. // If this is the last range we don't have to make this test
  3332. if( range < (int)ranges.GetLength() - 1 )
  3333. {
  3334. // If the value is larger than the largest case value in the range, jump to the next range
  3335. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3336. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3337. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3338. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3339. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3340. }
  3341. // Jump forward according to the value
  3342. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3343. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3344. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3345. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3346. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3347. // Add the list of jumps to the correct labels (any holes, jump to default)
  3348. index = ranges[range];
  3349. for( int n = caseValues[index]; n <= maxRange; n++ )
  3350. {
  3351. if( caseValues[index] == n )
  3352. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3353. else
  3354. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3355. }
  3356. expr.bc.Label((short)nextRangeLabel);
  3357. }
  3358. else
  3359. {
  3360. // Simply make a comparison with each value
  3361. int n;
  3362. for( n = ranges[range]; n < index; ++n )
  3363. {
  3364. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3365. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  3366. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3367. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  3368. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3369. }
  3370. }
  3371. }
  3372. // Catch any value that falls trough
  3373. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3374. // Release the temporary variable previously stored
  3375. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3376. // TODO: optimize: Should optimize each piece individually
  3377. expr.bc.OptimizeLocally(tempVariableOffsets);
  3378. //----------------------------------
  3379. // Output case implementations
  3380. //----------------------------------
  3381. // Compile case implementations, each one with the label before it
  3382. cnode = snode->firstChild->next;
  3383. while( cnode )
  3384. {
  3385. // Each case should have a constant expression
  3386. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3387. {
  3388. expr.bc.Label((short)firstCaseLabel++);
  3389. CompileCase(cnode->firstChild->next, &expr.bc);
  3390. }
  3391. else
  3392. {
  3393. expr.bc.Label((short)defaultLabel);
  3394. // Is default the last case?
  3395. if( cnode->next )
  3396. {
  3397. // We've already reported this error
  3398. break;
  3399. }
  3400. CompileCase(cnode->firstChild, &expr.bc);
  3401. }
  3402. cnode = cnode->next;
  3403. }
  3404. //--------------------------------
  3405. bc->AddCode(&expr.bc);
  3406. // Add break label
  3407. bc->Label((short)breakLabel);
  3408. breakLabels.PopLast();
  3409. RemoveVariableScope();
  3410. }
  3411. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3412. {
  3413. bool isFinished = false;
  3414. bool hasReturn = false;
  3415. bool hasUnreachableCode = false;
  3416. while( node )
  3417. {
  3418. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3419. {
  3420. hasUnreachableCode = true;
  3421. Warning(TXT_UNREACHABLE_CODE, node);
  3422. break;
  3423. }
  3424. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3425. isFinished = true;
  3426. asCByteCode statement(engine);
  3427. if( node->nodeType == snDeclaration )
  3428. {
  3429. Error(TXT_DECL_IN_SWITCH, node);
  3430. // Compile it anyway to avoid further compiler errors
  3431. CompileDeclaration(node, &statement);
  3432. }
  3433. else
  3434. CompileStatement(node, &hasReturn, &statement);
  3435. LineInstr(bc, node->tokenPos);
  3436. bc->AddCode(&statement);
  3437. if( !hasCompileErrors )
  3438. asASSERT( tempVariables.GetLength() == 0 );
  3439. node = node->next;
  3440. }
  3441. }
  3442. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3443. {
  3444. // We will use one label for the if statement
  3445. // and possibly another for the else statement
  3446. int afterLabel = nextLabel++;
  3447. // Compile the expression
  3448. asSExprContext expr(engine);
  3449. int r = CompileAssignment(inode->firstChild, &expr);
  3450. if( r == 0 )
  3451. {
  3452. // Allow value types to be converted to bool using 'bool opImplConv()'
  3453. if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  3454. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3455. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3456. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3457. else
  3458. {
  3459. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3460. ProcessDeferredParams(&expr);
  3461. if( !expr.type.isConstant )
  3462. {
  3463. ProcessPropertyGetAccessor(&expr, inode);
  3464. ConvertToVariable(&expr);
  3465. // Add a test
  3466. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3467. expr.bc.Instr(asBC_ClrHi);
  3468. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3469. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3470. expr.bc.OptimizeLocally(tempVariableOffsets);
  3471. bc->AddCode(&expr.bc);
  3472. }
  3473. else if( expr.type.dwordValue == 0 )
  3474. {
  3475. // Jump to the else case
  3476. bc->InstrINT(asBC_JMP, afterLabel);
  3477. // TODO: Should we warn that the expression will always go to the else?
  3478. }
  3479. }
  3480. }
  3481. // Compile the if statement
  3482. bool origIsConstructorCalled = m_isConstructorCalled;
  3483. bool hasReturn1;
  3484. asCByteCode ifBC(engine);
  3485. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3486. // Add the byte code
  3487. LineInstr(bc, inode->firstChild->next->tokenPos);
  3488. bc->AddCode(&ifBC);
  3489. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3490. {
  3491. // Don't allow if( expr );
  3492. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3493. }
  3494. // If one of the statements call the constructor, the other must as well
  3495. // otherwise it is possible the constructor is never called
  3496. bool constructorCall1 = false;
  3497. bool constructorCall2 = false;
  3498. if( !origIsConstructorCalled && m_isConstructorCalled )
  3499. constructorCall1 = true;
  3500. // Do we have an else statement?
  3501. if( inode->firstChild->next != inode->lastChild )
  3502. {
  3503. // Reset the constructor called flag so the else statement can call the constructor too
  3504. m_isConstructorCalled = origIsConstructorCalled;
  3505. int afterElse = 0;
  3506. if( !hasReturn1 )
  3507. {
  3508. afterElse = nextLabel++;
  3509. // Add jump to after the else statement
  3510. bc->InstrINT(asBC_JMP, afterElse);
  3511. }
  3512. // Add label for the else statement
  3513. bc->Label((short)afterLabel);
  3514. bool hasReturn2;
  3515. asCByteCode elseBC(engine);
  3516. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3517. // Add byte code for the else statement
  3518. LineInstr(bc, inode->lastChild->tokenPos);
  3519. bc->AddCode(&elseBC);
  3520. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3521. {
  3522. // Don't allow if( expr ) {} else;
  3523. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3524. }
  3525. if( !hasReturn1 )
  3526. {
  3527. // Add label for the end of else statement
  3528. bc->Label((short)afterElse);
  3529. }
  3530. // The if statement only has return if both alternatives have
  3531. *hasReturn = hasReturn1 && hasReturn2;
  3532. if( !origIsConstructorCalled && m_isConstructorCalled )
  3533. constructorCall2 = true;
  3534. }
  3535. else
  3536. {
  3537. // Add label for the end of if statement
  3538. bc->Label((short)afterLabel);
  3539. *hasReturn = false;
  3540. }
  3541. // Make sure both or neither conditions call a constructor
  3542. if( (constructorCall1 && !constructorCall2) ||
  3543. (constructorCall2 && !constructorCall1) )
  3544. {
  3545. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3546. }
  3547. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3548. }
  3549. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3550. {
  3551. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3552. AddVariableScope(true, true);
  3553. // We will use three labels for the for loop
  3554. int conditionLabel = nextLabel++;
  3555. int afterLabel = nextLabel++;
  3556. int continueLabel = nextLabel++;
  3557. int insideLabel = nextLabel++;
  3558. continueLabels.PushLast(continueLabel);
  3559. breakLabels.PushLast(afterLabel);
  3560. //---------------------------------------
  3561. // Compile the initialization statement
  3562. asCByteCode initBC(engine);
  3563. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3564. if( fnode->firstChild->nodeType == snDeclaration )
  3565. CompileDeclaration(fnode->firstChild, &initBC);
  3566. else
  3567. CompileExpressionStatement(fnode->firstChild, &initBC);
  3568. //-----------------------------------
  3569. // Compile the condition statement
  3570. asSExprContext expr(engine);
  3571. asCScriptNode *second = fnode->firstChild->next;
  3572. if( second->firstChild )
  3573. {
  3574. int r = CompileAssignment(second->firstChild, &expr);
  3575. if( r >= 0 )
  3576. {
  3577. // Allow value types to be converted to bool using 'bool opImplConv()'
  3578. if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  3579. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3580. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3581. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3582. else
  3583. {
  3584. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3585. ProcessDeferredParams(&expr);
  3586. ProcessPropertyGetAccessor(&expr, second);
  3587. // If expression is false exit the loop
  3588. ConvertToVariable(&expr);
  3589. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3590. expr.bc.Instr(asBC_ClrHi);
  3591. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3592. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3593. expr.bc.OptimizeLocally(tempVariableOffsets);
  3594. // Prepend the line instruction for the condition
  3595. asCByteCode tmp(engine);
  3596. LineInstr(&tmp, second->firstChild->tokenPos);
  3597. tmp.AddCode(&expr.bc);
  3598. expr.bc.AddCode(&tmp);
  3599. }
  3600. }
  3601. }
  3602. //---------------------------
  3603. // Compile the increment statement(s)
  3604. asCByteCode nextBC(engine);
  3605. asCScriptNode *cnode = second->next;
  3606. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3607. {
  3608. LineInstr(&nextBC, cnode->tokenPos);
  3609. CompileExpressionStatement(cnode, &nextBC);
  3610. cnode = cnode->next;
  3611. }
  3612. //------------------------------
  3613. // Compile loop statement
  3614. bool hasReturn;
  3615. asCByteCode forBC(engine);
  3616. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3617. //-------------------------------
  3618. // Join the code pieces
  3619. bc->AddCode(&initBC);
  3620. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3621. bc->Label((short)insideLabel);
  3622. // Add a suspend bytecode inside the loop to guarantee
  3623. // that the application can suspend the execution
  3624. bc->Instr(asBC_SUSPEND);
  3625. bc->InstrPTR(asBC_JitEntry, 0);
  3626. LineInstr(bc, fnode->lastChild->tokenPos);
  3627. bc->AddCode(&forBC);
  3628. bc->Label((short)continueLabel);
  3629. bc->AddCode(&nextBC);
  3630. bc->Label((short)conditionLabel);
  3631. if( expr.bc.GetLastInstr() == -1 )
  3632. // There is no condition, so we just always jump
  3633. bc->InstrDWORD(asBC_JMP, insideLabel);
  3634. else
  3635. bc->AddCode(&expr.bc);
  3636. bc->Label((short)afterLabel);
  3637. continueLabels.PopLast();
  3638. breakLabels.PopLast();
  3639. // Deallocate variables in this block, in reverse order
  3640. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3641. {
  3642. sVariable *v = variables->variables[n];
  3643. // Call variable destructors here, for variables not yet destroyed
  3644. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3645. // Don't deallocate function parameters
  3646. if( v->stackOffset > 0 )
  3647. DeallocateVariable(v->stackOffset);
  3648. }
  3649. RemoveVariableScope();
  3650. }
  3651. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3652. {
  3653. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3654. AddVariableScope(true, true);
  3655. // We will use two labels for the while loop
  3656. int beforeLabel = nextLabel++;
  3657. int afterLabel = nextLabel++;
  3658. continueLabels.PushLast(beforeLabel);
  3659. breakLabels.PushLast(afterLabel);
  3660. // Add label before the expression
  3661. bc->Label((short)beforeLabel);
  3662. // Compile expression
  3663. asSExprContext expr(engine);
  3664. int r = CompileAssignment(wnode->firstChild, &expr);
  3665. if( r == 0 )
  3666. {
  3667. // Allow value types to be converted to bool using 'bool opImplConv()'
  3668. if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  3669. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3670. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3671. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3672. else
  3673. {
  3674. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3675. ProcessDeferredParams(&expr);
  3676. ProcessPropertyGetAccessor(&expr, wnode);
  3677. // Add byte code for the expression
  3678. ConvertToVariable(&expr);
  3679. // Jump to end of statement if expression is false
  3680. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3681. expr.bc.Instr(asBC_ClrHi);
  3682. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3683. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3684. expr.bc.OptimizeLocally(tempVariableOffsets);
  3685. bc->AddCode(&expr.bc);
  3686. }
  3687. }
  3688. // Add a suspend bytecode inside the loop to guarantee
  3689. // that the application can suspend the execution
  3690. bc->Instr(asBC_SUSPEND);
  3691. bc->InstrPTR(asBC_JitEntry, 0);
  3692. // Compile statement
  3693. bool hasReturn;
  3694. asCByteCode whileBC(engine);
  3695. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3696. // Add byte code for the statement
  3697. LineInstr(bc, wnode->lastChild->tokenPos);
  3698. bc->AddCode(&whileBC);
  3699. // Jump to the expression
  3700. bc->InstrINT(asBC_JMP, beforeLabel);
  3701. // Add label after the statement
  3702. bc->Label((short)afterLabel);
  3703. continueLabels.PopLast();
  3704. breakLabels.PopLast();
  3705. RemoveVariableScope();
  3706. }
  3707. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3708. {
  3709. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3710. AddVariableScope(true, true);
  3711. // We will use two labels for the while loop
  3712. int beforeLabel = nextLabel++;
  3713. int beforeTest = nextLabel++;
  3714. int afterLabel = nextLabel++;
  3715. continueLabels.PushLast(beforeTest);
  3716. breakLabels.PushLast(afterLabel);
  3717. // Add label before the statement
  3718. bc->Label((short)beforeLabel);
  3719. // Compile statement
  3720. bool hasReturn;
  3721. asCByteCode whileBC(engine);
  3722. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3723. // Add byte code for the statement
  3724. LineInstr(bc, wnode->firstChild->tokenPos);
  3725. bc->AddCode(&whileBC);
  3726. // Add label before the expression
  3727. bc->Label((short)beforeTest);
  3728. // Add a suspend bytecode inside the loop to guarantee
  3729. // that the application can suspend the execution
  3730. bc->Instr(asBC_SUSPEND);
  3731. bc->InstrPTR(asBC_JitEntry, 0);
  3732. // Add a line instruction
  3733. LineInstr(bc, wnode->lastChild->tokenPos);
  3734. // Compile expression
  3735. asSExprContext expr(engine);
  3736. CompileAssignment(wnode->lastChild, &expr);
  3737. // Allow value types to be converted to bool using 'bool opImplConv()'
  3738. if( expr.type.dataType.GetObjectType() && (expr.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  3739. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  3740. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3741. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3742. else
  3743. {
  3744. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3745. ProcessDeferredParams(&expr);
  3746. ProcessPropertyGetAccessor(&expr, wnode);
  3747. // Add byte code for the expression
  3748. ConvertToVariable(&expr);
  3749. // Jump to next iteration if expression is true
  3750. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3751. expr.bc.Instr(asBC_ClrHi);
  3752. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3753. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3754. expr.bc.OptimizeLocally(tempVariableOffsets);
  3755. bc->AddCode(&expr.bc);
  3756. }
  3757. // Add label after the statement
  3758. bc->Label((short)afterLabel);
  3759. continueLabels.PopLast();
  3760. breakLabels.PopLast();
  3761. RemoveVariableScope();
  3762. }
  3763. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3764. {
  3765. if( breakLabels.GetLength() == 0 )
  3766. {
  3767. Error(TXT_INVALID_BREAK, node);
  3768. return;
  3769. }
  3770. // Add destructor calls for all variables that will go out of scope
  3771. // Put this clean up in a block to allow exception handler to understand them
  3772. bc->Block(true);
  3773. asCVariableScope *vs = variables;
  3774. while( !vs->isBreakScope )
  3775. {
  3776. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3777. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3778. vs = vs->parent;
  3779. }
  3780. bc->Block(false);
  3781. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  3782. }
  3783. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  3784. {
  3785. if( continueLabels.GetLength() == 0 )
  3786. {
  3787. Error(TXT_INVALID_CONTINUE, node);
  3788. return;
  3789. }
  3790. // Add destructor calls for all variables that will go out of scope
  3791. // Put this clean up in a block to allow exception handler to understand them
  3792. bc->Block(true);
  3793. asCVariableScope *vs = variables;
  3794. while( !vs->isContinueScope )
  3795. {
  3796. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3797. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3798. vs = vs->parent;
  3799. }
  3800. bc->Block(false);
  3801. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  3802. }
  3803. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  3804. {
  3805. if( enode->firstChild )
  3806. {
  3807. // Compile the expression
  3808. asSExprContext expr(engine);
  3809. CompileAssignment(enode->firstChild, &expr);
  3810. // Must not have unused ambiguous names
  3811. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  3812. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  3813. // Must not have unused anonymous functions
  3814. if( expr.IsLambda() )
  3815. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  3816. // If we get here and there is still an unprocessed property
  3817. // accessor, then process it as a get access. Don't call if there is
  3818. // already a compile error, or we might report an error that is not valid
  3819. if( !hasCompileErrors )
  3820. ProcessPropertyGetAccessor(&expr, enode);
  3821. // Pop the value from the stack
  3822. if( !expr.type.dataType.IsPrimitive() )
  3823. expr.bc.Instr(asBC_PopPtr);
  3824. // Release temporary variables used by expression
  3825. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3826. ProcessDeferredParams(&expr);
  3827. expr.bc.OptimizeLocally(tempVariableOffsets);
  3828. bc->AddCode(&expr.bc);
  3829. }
  3830. }
  3831. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  3832. {
  3833. // If the object already is stored in temporary variable then nothing needs to be done
  3834. // Note, a type can be temporary without being a variable, in which case it is holding off
  3835. // on releasing a previously used object.
  3836. if( ctx->type.isTemporary && ctx->type.isVariable &&
  3837. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  3838. {
  3839. // If the temporary object is currently not a reference
  3840. // the expression needs to be reevaluated to a reference
  3841. if( !ctx->type.dataType.IsReference() )
  3842. {
  3843. ctx->bc.Instr(asBC_PopPtr);
  3844. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3845. ctx->type.dataType.MakeReference(true);
  3846. }
  3847. return;
  3848. }
  3849. // Allocate temporary variable
  3850. asCDataType dt = ctx->type.dataType;
  3851. dt.MakeReference(false);
  3852. dt.MakeReadOnly(false);
  3853. int offset = AllocateVariable(dt, true, forceOnHeap);
  3854. // Objects stored on the stack are not considered references
  3855. dt.MakeReference(IsVariableOnHeap(offset));
  3856. asCTypeInfo lvalue;
  3857. lvalue.Set(dt);
  3858. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  3859. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3860. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  3861. // Push the reference to the temporary variable on the stack
  3862. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3863. ctx->type.Set(dt);
  3864. ctx->type.isTemporary = true;
  3865. ctx->type.stackOffset = (short)offset;
  3866. ctx->type.isVariable = true;
  3867. ctx->type.isExplicitHandle = isExplicitHandle;
  3868. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  3869. }
  3870. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  3871. {
  3872. // Get return type and location
  3873. sVariable *v = variables->GetVariable("return");
  3874. // Basic validations
  3875. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  3876. {
  3877. Error(TXT_MUST_RETURN_VALUE, rnode);
  3878. return;
  3879. }
  3880. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  3881. {
  3882. Error(TXT_CANT_RETURN_VALUE, rnode);
  3883. return;
  3884. }
  3885. // Compile the expression
  3886. if( rnode->firstChild )
  3887. {
  3888. // Compile the expression
  3889. asSExprContext expr(engine);
  3890. int r = CompileAssignment(rnode->firstChild, &expr);
  3891. if( r < 0 ) return;
  3892. if( v->type.IsReference() )
  3893. {
  3894. // The expression that gives the reference must not use any of the
  3895. // variables that must be destroyed upon exit, because then it means
  3896. // reference will stay alive while the clean-up is done, which could
  3897. // potentially mean that the reference is invalidated by the clean-up.
  3898. //
  3899. // When the function is returning a reference, the clean-up of the
  3900. // variables must be done before the evaluation of the expression.
  3901. //
  3902. // A reference to a global variable, or a class member for class methods
  3903. // should be allowed to be returned.
  3904. if( !(expr.type.dataType.IsReference() ||
  3905. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  3906. {
  3907. // Clean up the potential deferred parameters
  3908. ProcessDeferredParams(&expr);
  3909. Error(TXT_NOT_VALID_REFERENCE, rnode);
  3910. return;
  3911. }
  3912. // No references to local variables, temporary variables, or parameters
  3913. // are allowed to be returned, since they go out of scope when the function
  3914. // returns. Even reference parameters are disallowed, since it is not possible
  3915. // to know the scope of them. The exception is the 'this' pointer, which
  3916. // is treated by the compiler as a local variable, but isn't really so.
  3917. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  3918. {
  3919. // Clean up the potential deferred parameters
  3920. ProcessDeferredParams(&expr);
  3921. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  3922. return;
  3923. }
  3924. // The type must match exactly as we cannot convert
  3925. // the reference without loosing the original value
  3926. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  3927. (expr.type.dataType.IsObject() &&
  3928. !expr.type.dataType.IsObjectHandle() &&
  3929. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  3930. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  3931. {
  3932. // Clean up the potential deferred parameters
  3933. ProcessDeferredParams(&expr);
  3934. asCString str;
  3935. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  3936. Error(str, rnode);
  3937. return;
  3938. }
  3939. // The expression must not have any deferred expressions, because the evaluation
  3940. // of these cannot be done without keeping the reference which is not safe
  3941. if( expr.deferredParams.GetLength() )
  3942. {
  3943. // Clean up the potential deferred parameters
  3944. ProcessDeferredParams(&expr);
  3945. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  3946. return;
  3947. }
  3948. // Make sure the expression isn't using any local variables that
  3949. // will need to be cleaned up before the function completes
  3950. asCArray<int> usedVars;
  3951. expr.bc.GetVarsUsed(usedVars);
  3952. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  3953. {
  3954. int var = GetVariableSlot(usedVars[n]);
  3955. if( var != -1 )
  3956. {
  3957. asCDataType dt = variableAllocations[var];
  3958. if( dt.IsObject() )
  3959. {
  3960. ProcessDeferredParams(&expr);
  3961. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  3962. return;
  3963. }
  3964. }
  3965. }
  3966. // Can't return the reference if could point to a local variable
  3967. if( expr.type.isRefToLocal )
  3968. {
  3969. ProcessDeferredParams(&expr);
  3970. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  3971. return;
  3972. }
  3973. // All objects in the function must be cleaned up before the expression
  3974. // is evaluated, otherwise there is a possibility that the cleanup will
  3975. // invalidate the reference.
  3976. // Destroy the local variables before loading
  3977. // the reference into the register. This will
  3978. // be done before the expression is evaluated.
  3979. DestroyVariables(bc);
  3980. // For primitives the reference is already in the register,
  3981. // but for non-primitives the reference is on the stack so we
  3982. // need to load it into the register
  3983. if( !expr.type.dataType.IsPrimitive() )
  3984. {
  3985. if( !expr.type.dataType.IsObjectHandle() &&
  3986. expr.type.dataType.IsReference() )
  3987. expr.bc.Instr(asBC_RDSPtr);
  3988. expr.bc.Instr(asBC_PopRPtr);
  3989. }
  3990. // There are no temporaries to release so we're done
  3991. }
  3992. else // if( !v->type.IsReference() )
  3993. {
  3994. ProcessPropertyGetAccessor(&expr, rnode);
  3995. // Prepare the value for assignment
  3996. IsVariableInitialized(&expr.type, rnode->firstChild);
  3997. if( v->type.IsPrimitive() )
  3998. {
  3999. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4000. // Implicitly convert the value to the return type
  4001. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4002. // Verify that the conversion was successful
  4003. if( expr.type.dataType != v->type )
  4004. {
  4005. asCString str;
  4006. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4007. Error(str, rnode);
  4008. return;
  4009. }
  4010. else
  4011. {
  4012. ConvertToVariable(&expr);
  4013. // Clean up the local variables and process deferred parameters
  4014. DestroyVariables(&expr.bc);
  4015. ProcessDeferredParams(&expr);
  4016. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4017. // Load the variable in the register
  4018. if( v->type.GetSizeOnStackDWords() == 1 )
  4019. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4020. else
  4021. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4022. }
  4023. }
  4024. else if( v->type.IsObject() )
  4025. {
  4026. // Value types are returned on the stack, in a location
  4027. // that has been reserved by the calling function.
  4028. if( outFunc->DoesReturnOnStack() )
  4029. {
  4030. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4031. // it should be called directly instead of first converting the expression and
  4032. // then copy the value.
  4033. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4034. {
  4035. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4036. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4037. {
  4038. asCString str;
  4039. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4040. Error(str, rnode->firstChild);
  4041. return;
  4042. }
  4043. }
  4044. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4045. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4046. // Clean up the local variables and process deferred parameters
  4047. DestroyVariables(&expr.bc);
  4048. ProcessDeferredParams(&expr);
  4049. }
  4050. else
  4051. {
  4052. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  4053. // Prepare the expression to be loaded into the object
  4054. // register. This will place the reference in local variable
  4055. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4056. // Pop the reference to the temporary variable
  4057. expr.bc.Instr(asBC_PopPtr);
  4058. // Clean up the local variables and process deferred parameters
  4059. DestroyVariables(&expr.bc);
  4060. ProcessDeferredParams(&expr);
  4061. // Load the object pointer into the object register
  4062. // LOADOBJ also clears the address in the variable
  4063. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4064. // LOADOBJ cleared the address in the variable so the object will not be freed
  4065. // here, but the temporary variable must still be freed so the slot can be reused
  4066. // By releasing without the bytecode we do just that.
  4067. ReleaseTemporaryVariable(expr.type, 0);
  4068. }
  4069. }
  4070. }
  4071. expr.bc.OptimizeLocally(tempVariableOffsets);
  4072. bc->AddCode(&expr.bc);
  4073. }
  4074. else
  4075. {
  4076. // For functions that don't return anything
  4077. // we just detroy the local variables
  4078. DestroyVariables(bc);
  4079. }
  4080. // Jump to the end of the function
  4081. bc->InstrINT(asBC_JMP, 0);
  4082. }
  4083. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4084. {
  4085. // Call destructor on all variables except for the function parameters
  4086. // Put the clean-up in a block to allow exception handler to understand this
  4087. bc->Block(true);
  4088. asCVariableScope *vs = variables;
  4089. while( vs )
  4090. {
  4091. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4092. if( vs->variables[n]->stackOffset > 0 )
  4093. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4094. vs = vs->parent;
  4095. }
  4096. bc->Block(false);
  4097. }
  4098. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4099. {
  4100. variables = asNEW(asCVariableScope)(variables);
  4101. if( variables == 0 )
  4102. {
  4103. // Out of memory
  4104. return;
  4105. }
  4106. variables->isBreakScope = isBreakScope;
  4107. variables->isContinueScope = isContinueScope;
  4108. }
  4109. void asCCompiler::RemoveVariableScope()
  4110. {
  4111. if( variables )
  4112. {
  4113. asCVariableScope *var = variables;
  4114. variables = variables->parent;
  4115. asDELETE(var,asCVariableScope);
  4116. }
  4117. }
  4118. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4119. {
  4120. asCString str;
  4121. int r = 0, c = 0;
  4122. asASSERT( node );
  4123. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4124. builder->WriteError(script->name, msg, r, c);
  4125. hasCompileErrors = true;
  4126. }
  4127. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4128. {
  4129. asCString str;
  4130. int r = 0, c = 0;
  4131. asASSERT( node );
  4132. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4133. builder->WriteWarning(script->name, msg, r, c);
  4134. }
  4135. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4136. {
  4137. asCString str;
  4138. int r = 0, c = 0;
  4139. asASSERT( node );
  4140. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4141. builder->WriteInfo(script->name, msg, r, c, false);
  4142. }
  4143. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4144. {
  4145. int r = 0, c = 0;
  4146. asASSERT( node );
  4147. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4148. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4149. {
  4150. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4151. if( inType && func->funcType == asFUNC_VIRTUAL )
  4152. func = inType->virtualFunctionTable[func->vfTableIdx];
  4153. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4154. }
  4155. }
  4156. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  4157. {
  4158. int l = int(reservedVariables.GetLength());
  4159. ctx->bc.GetVarsUsed(reservedVariables);
  4160. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4161. reservedVariables.SetLength(l);
  4162. return var;
  4163. }
  4164. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  4165. {
  4166. asCDataType t(type);
  4167. t.MakeReference(false);
  4168. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4169. t.SetTokenType(ttInt);
  4170. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4171. t.SetTokenType(ttDouble);
  4172. // Only null handles have the token type unrecognized token
  4173. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4174. bool isOnHeap = true;
  4175. if( t.IsPrimitive() ||
  4176. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  4177. {
  4178. // Primitives and value types (unless overridden) are allocated on the stack
  4179. isOnHeap = false;
  4180. }
  4181. // Find a free location with the same type
  4182. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4183. {
  4184. int slot = freeVariables[n];
  4185. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4186. variableIsTemporary[slot] == isTemporary &&
  4187. variableIsOnHeap[slot] == isOnHeap )
  4188. {
  4189. // We can't return by slot, must count variable sizes
  4190. int offset = GetVariableOffset(slot);
  4191. // Verify that it is not in the list of reserved variables
  4192. bool isUsed = false;
  4193. if( reservedVariables.GetLength() )
  4194. isUsed = reservedVariables.Exists(offset);
  4195. if( !isUsed )
  4196. {
  4197. if( n != freeVariables.GetLength() - 1 )
  4198. freeVariables[n] = freeVariables.PopLast();
  4199. else
  4200. freeVariables.PopLast();
  4201. if( isTemporary )
  4202. tempVariables.PushLast(offset);
  4203. return offset;
  4204. }
  4205. }
  4206. }
  4207. variableAllocations.PushLast(t);
  4208. variableIsTemporary.PushLast(isTemporary);
  4209. variableIsOnHeap.PushLast(isOnHeap);
  4210. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4211. if( isTemporary )
  4212. {
  4213. // Add offset to the currently allocated temporary variables
  4214. tempVariables.PushLast(offset);
  4215. // Add offset to all known offsets to temporary variables, whether allocated or not
  4216. tempVariableOffsets.PushLast(offset);
  4217. }
  4218. return offset;
  4219. }
  4220. int asCCompiler::GetVariableOffset(int varIndex)
  4221. {
  4222. // Return offset to the last dword on the stack
  4223. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4224. int varOffset = 1;
  4225. // Skip lower variables
  4226. for( int n = 0; n < varIndex; n++ )
  4227. {
  4228. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4229. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4230. else
  4231. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4232. }
  4233. if( varIndex < (int)variableAllocations.GetLength() )
  4234. {
  4235. // For variables larger than 1 dword the returned offset should be to the last dword
  4236. int size;
  4237. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4238. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4239. else
  4240. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4241. if( size > 1 )
  4242. varOffset += size-1;
  4243. }
  4244. return varOffset;
  4245. }
  4246. int asCCompiler::GetVariableSlot(int offset)
  4247. {
  4248. int varOffset = 1;
  4249. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4250. {
  4251. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4252. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4253. else
  4254. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4255. if( varOffset == offset )
  4256. return n;
  4257. varOffset++;
  4258. }
  4259. return -1;
  4260. }
  4261. bool asCCompiler::IsVariableOnHeap(int offset)
  4262. {
  4263. int varSlot = GetVariableSlot(offset);
  4264. if( varSlot < 0 )
  4265. {
  4266. // This happens for function arguments that are considered as on the heap
  4267. return true;
  4268. }
  4269. return variableIsOnHeap[varSlot];
  4270. }
  4271. void asCCompiler::DeallocateVariable(int offset)
  4272. {
  4273. // Remove temporary variable
  4274. int n;
  4275. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4276. {
  4277. if( offset == tempVariables[n] )
  4278. {
  4279. if( n == (int)tempVariables.GetLength()-1 )
  4280. tempVariables.PopLast();
  4281. else
  4282. tempVariables[n] = tempVariables.PopLast();
  4283. break;
  4284. }
  4285. }
  4286. n = GetVariableSlot(offset);
  4287. if( n != -1 )
  4288. {
  4289. freeVariables.PushLast(n);
  4290. return;
  4291. }
  4292. // We might get here if the variable was implicitly declared
  4293. // because it was use before a formal declaration, in this case
  4294. // the offset is 0x7FFF
  4295. asASSERT(offset == 0x7FFF);
  4296. }
  4297. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  4298. {
  4299. if( t.isTemporary )
  4300. {
  4301. ReleaseTemporaryVariable(t.stackOffset, bc);
  4302. t.isTemporary = false;
  4303. }
  4304. }
  4305. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4306. {
  4307. asASSERT( tempVariables.Exists(offset) );
  4308. if( bc )
  4309. {
  4310. // We need to call the destructor on the true variable type
  4311. int n = GetVariableSlot(offset);
  4312. asASSERT( n >= 0 );
  4313. if( n >= 0 )
  4314. {
  4315. asCDataType dt = variableAllocations[n];
  4316. bool isOnHeap = variableIsOnHeap[n];
  4317. // Call destructor
  4318. CallDestructor(dt, offset, isOnHeap, bc);
  4319. }
  4320. }
  4321. DeallocateVariable(offset);
  4322. }
  4323. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  4324. {
  4325. if( ctx->type.dataType.IsReference() )
  4326. {
  4327. if( ctx->type.dataType.IsObject() )
  4328. {
  4329. ctx->type.dataType.MakeReference(false);
  4330. if( generateCode )
  4331. ctx->bc.Instr(asBC_RDSPtr);
  4332. }
  4333. else
  4334. {
  4335. // This should never happen as primitives are treated differently
  4336. asASSERT(false);
  4337. }
  4338. }
  4339. }
  4340. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  4341. {
  4342. // No need to check if there is no variable scope
  4343. if( variables == 0 ) return true;
  4344. // Temporary variables are assumed to be initialized
  4345. if( type->isTemporary ) return true;
  4346. // Verify that it is a variable
  4347. if( !type->isVariable ) return true;
  4348. // Find the variable
  4349. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4350. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4351. if( v == 0 ) return true;
  4352. if( v->isInitialized ) return true;
  4353. // Complex types don't need this test
  4354. if( v->type.IsObject() ) return true;
  4355. // Mark as initialized so that the user will not be bothered again
  4356. v->isInitialized = true;
  4357. // Write warning
  4358. asCString str;
  4359. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4360. Warning(str, node);
  4361. return false;
  4362. }
  4363. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  4364. {
  4365. // Check if the variable is initialized (if it indeed is a variable)
  4366. IsVariableInitialized(&ctx->type, node);
  4367. asCDataType to = ctx->type.dataType;
  4368. to.MakeReference(false);
  4369. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4370. ProcessDeferredParams(ctx);
  4371. }
  4372. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  4373. {
  4374. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4375. int l = int(reservedVariables.GetLength());
  4376. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4377. ProcessPropertyGetAccessor(rctx, node);
  4378. // Make sure the rvalue is initialized if it is a variable
  4379. IsVariableInitialized(&rctx->type, node);
  4380. if( lvalue->IsPrimitive() )
  4381. {
  4382. if( rctx->type.dataType.IsPrimitive() )
  4383. {
  4384. if( rctx->type.dataType.IsReference() )
  4385. {
  4386. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4387. ConvertToVariableNotIn(rctx, lvalueExpr);
  4388. }
  4389. }
  4390. // Implicitly convert the value to the right type
  4391. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4392. // Check data type
  4393. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4394. {
  4395. asCString str;
  4396. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4397. Error(str, node);
  4398. rctx->type.SetDummy();
  4399. }
  4400. // Make sure the rvalue is a variable
  4401. if( !rctx->type.isVariable )
  4402. ConvertToVariableNotIn(rctx, lvalueExpr);
  4403. }
  4404. else
  4405. {
  4406. asCDataType to = *lvalue;
  4407. to.MakeReference(false);
  4408. // TODO: ImplicitConversion should know to do this by itself
  4409. // First convert to a handle which will do a reference cast
  4410. if( !lvalue->IsObjectHandle() &&
  4411. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4412. to.MakeHandle(true);
  4413. // Don't allow the implicit conversion to create an object
  4414. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4415. if( !lvalue->IsObjectHandle() &&
  4416. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4417. {
  4418. // Then convert to a reference, which will validate the handle
  4419. to.MakeHandle(false);
  4420. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4421. }
  4422. // Check data type
  4423. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4424. {
  4425. asCString str;
  4426. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4427. Error(str, node);
  4428. }
  4429. else
  4430. {
  4431. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4432. if( lvalue->IsObject() )
  4433. asASSERT(!rctx->type.dataType.IsReference());
  4434. }
  4435. }
  4436. // Unreserve variables
  4437. reservedVariables.SetLength(l);
  4438. }
  4439. bool asCCompiler::IsLValue(asCTypeInfo &type)
  4440. {
  4441. if( !type.isLValue ) return false;
  4442. if( type.dataType.IsReadOnly() ) return false;
  4443. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4444. return true;
  4445. }
  4446. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  4447. {
  4448. if( lvalue->dataType.IsReadOnly() )
  4449. {
  4450. Error(TXT_REF_IS_READ_ONLY, node);
  4451. return -1;
  4452. }
  4453. if( lvalue->dataType.IsPrimitive() )
  4454. {
  4455. if( lvalue->isVariable )
  4456. {
  4457. // Copy the value between the variables directly
  4458. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4459. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4460. else
  4461. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4462. // Mark variable as initialized
  4463. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4464. if( v ) v->isInitialized = true;
  4465. }
  4466. else if( lvalue->dataType.IsReference() )
  4467. {
  4468. // Copy the value of the variable to the reference in the register
  4469. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4470. if( s == 1 )
  4471. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4472. else if( s == 2 )
  4473. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4474. else if( s == 4 )
  4475. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4476. else if( s == 8 )
  4477. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4478. }
  4479. else
  4480. {
  4481. Error(TXT_NOT_VALID_LVALUE, node);
  4482. return -1;
  4483. }
  4484. }
  4485. else if( !lvalue->isExplicitHandle )
  4486. {
  4487. asSExprContext ctx(engine);
  4488. ctx.type = *lvalue;
  4489. Dereference(&ctx, true);
  4490. *lvalue = ctx.type;
  4491. bc->AddCode(&ctx.bc);
  4492. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4493. if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4494. {
  4495. asSExprContext res(engine);
  4496. PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType());
  4497. bc->AddCode(&res.bc);
  4498. *lvalue = res.type;
  4499. }
  4500. else if( beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4501. {
  4502. // Call the default copy operator for script classes
  4503. // This is done differently because the default copy operator
  4504. // is registered as returning int&, but in reality it returns
  4505. // a reference to the object.
  4506. // TODO: Avoid this special case by implementing a copystub for
  4507. // script classes that uses the default copy operator
  4508. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4509. bc->Instr(asBC_PshRPtr);
  4510. }
  4511. else
  4512. {
  4513. // Default copy operator
  4514. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4515. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  4516. {
  4517. asCString msg;
  4518. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  4519. Error(msg, node);
  4520. return -1;
  4521. }
  4522. // Copy larger data types from a reference
  4523. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4524. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4525. }
  4526. }
  4527. else
  4528. {
  4529. // TODO: The object handle can be stored in a variable as well
  4530. if( !lvalue->dataType.IsReference() )
  4531. {
  4532. Error(TXT_NOT_VALID_REFERENCE, node);
  4533. return -1;
  4534. }
  4535. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  4536. // Mark variable as initialized
  4537. if( variables )
  4538. {
  4539. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4540. if( v ) v->isInitialized = true;
  4541. }
  4542. }
  4543. return 0;
  4544. }
  4545. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4546. {
  4547. bool conversionDone = false;
  4548. asCArray<int> ops;
  4549. asUINT n;
  4550. // A ref cast must not remove the constness
  4551. bool isConst = ctx->type.dataType.IsObjectConst();
  4552. // Find a suitable opCast or opImplCast method
  4553. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  4554. for( n = 0; n < ot->methods.GetLength(); n++ )
  4555. {
  4556. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4557. if( (isExplicit && func->name == "opCast") ||
  4558. func->name == "opImplCast" )
  4559. {
  4560. // Is the operator for the output type?
  4561. if( func->returnType.GetObjectType() != to.GetObjectType() )
  4562. continue;
  4563. // Can't call a non-const function on a const object
  4564. if( isConst && !func->IsReadOnly() )
  4565. continue;
  4566. ops.PushLast(func->id);
  4567. }
  4568. }
  4569. // Filter the list by constness to remove const methods if there are matching non-const methods
  4570. FilterConst(ops, !isConst);
  4571. // It shouldn't be possible to have more than one
  4572. // TODO: Should be allowed to have different behaviours for const and non-const references
  4573. asASSERT( ops.GetLength() <= 1 );
  4574. // Should only have one behaviour for each output type
  4575. if( ops.GetLength() == 1 )
  4576. {
  4577. conversionDone = true;
  4578. if( generateCode )
  4579. {
  4580. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4581. // null, we can create a special CALLSYS instruction that checks
  4582. // if the object pointer is null and if so sets the object register
  4583. // to null directly without executing the function.
  4584. //
  4585. // Alternatively I could force the ref cast behaviours be global
  4586. // functions with 1 parameter, even though they should still be
  4587. // registered with RegisterObjectBehaviour()
  4588. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_REF )
  4589. {
  4590. // Add code to avoid calling the cast behaviour if the handle is already null,
  4591. // because that will raise a null pointer exception due to the cast behaviour
  4592. // being a class method, and the this pointer cannot be null.
  4593. if( !ctx->type.isVariable )
  4594. {
  4595. Dereference(ctx, true);
  4596. ConvertToVariable(ctx);
  4597. }
  4598. // The reference on the stack will not be used
  4599. ctx->bc.Instr(asBC_PopPtr);
  4600. // TODO: runtime optimize: should have immediate comparison for null pointer
  4601. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4602. // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
  4603. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4604. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4605. DeallocateVariable(offset);
  4606. int afterLabel = nextLabel++;
  4607. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4608. // Call the cast operator
  4609. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4610. ctx->bc.Instr(asBC_RDSPtr);
  4611. ctx->type.dataType.MakeReference(false);
  4612. asCArray<asSExprContext *> args;
  4613. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4614. ctx->bc.Instr(asBC_PopPtr);
  4615. int endLabel = nextLabel++;
  4616. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4617. ctx->bc.Label((short)afterLabel);
  4618. // Make a NULL pointer
  4619. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4620. ctx->bc.Label((short)endLabel);
  4621. // Push the reference to the handle on the stack
  4622. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4623. }
  4624. else
  4625. {
  4626. // Value types cannot be null, so there is no need to check for this
  4627. // Call the cast operator
  4628. asCArray<asSExprContext *> args;
  4629. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4630. }
  4631. }
  4632. else
  4633. {
  4634. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4635. ctx->type.Set(func->returnType);
  4636. }
  4637. }
  4638. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4639. {
  4640. // Check for the generic ref cast method: void opCast(?&out)
  4641. for( n = 0; n < ot->methods.GetLength(); n++ )
  4642. {
  4643. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4644. if( (isExplicit && func->name == "opCast") ||
  4645. func->name == "opImplCast" )
  4646. {
  4647. // Does the operator take the ?&out parameter?
  4648. if( func->returnType.GetTokenType() != ttVoid ||
  4649. func->parameterTypes.GetLength() != 1 ||
  4650. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4651. func->inOutFlags[0] != asTM_OUTREF )
  4652. continue;
  4653. ops.PushLast(func->id);
  4654. }
  4655. }
  4656. // It shouldn't be possible to have more than one
  4657. // TODO: Should be allowed to have different implementations for const and non-const references
  4658. asASSERT( ops.GetLength() <= 1 );
  4659. if( ops.GetLength() == 1 )
  4660. {
  4661. conversionDone = true;
  4662. if( generateCode )
  4663. {
  4664. asASSERT(to.IsObjectHandle());
  4665. // Allocate a temporary variable of the requested handle type
  4666. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  4667. // Pass the reference of that variable to the function as output parameter
  4668. asCDataType toRef(to);
  4669. toRef.MakeReference(true);
  4670. asCArray<asSExprContext *> args;
  4671. asSExprContext arg(engine);
  4672. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4673. // Don't mark the variable as temporary, so it won't be freed too early
  4674. arg.type.SetVariable(toRef, stackOffset, false);
  4675. arg.type.isLValue = true;
  4676. arg.type.isExplicitHandle = true;
  4677. args.PushLast(&arg);
  4678. // Call the behaviour method
  4679. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4680. // Use the reference to the variable as the result of the expression
  4681. // Now we can mark the variable as temporary
  4682. ctx->type.SetVariable(toRef, stackOffset, true);
  4683. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4684. }
  4685. else
  4686. {
  4687. // All casts are legal
  4688. ctx->type.Set(to);
  4689. }
  4690. }
  4691. }
  4692. // If the script object didn't implement a matching opCast or opImplCast
  4693. // then check if the desired type is part of the hierarchy
  4694. if( !conversionDone && (ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4695. {
  4696. // We need it to be a reference
  4697. if( !ctx->type.dataType.IsReference() )
  4698. {
  4699. asCDataType to = ctx->type.dataType;
  4700. to.MakeReference(true);
  4701. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  4702. }
  4703. if( isExplicit )
  4704. {
  4705. // Allow dynamic cast between object handles (only for script objects).
  4706. // At run time this may result in a null handle,
  4707. // which when used will throw an exception
  4708. conversionDone = true;
  4709. if( generateCode )
  4710. {
  4711. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  4712. // Allocate a temporary variable for the returned object
  4713. int returnOffset = AllocateVariable(to, true);
  4714. // Move the pointer from the object register to the temporary variable
  4715. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  4716. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  4717. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4718. ctx->type.SetVariable(to, returnOffset, true);
  4719. ctx->type.dataType.MakeReference(true);
  4720. }
  4721. else
  4722. {
  4723. ctx->type.dataType = to;
  4724. ctx->type.dataType.MakeReference(true);
  4725. }
  4726. }
  4727. else
  4728. {
  4729. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4730. {
  4731. conversionDone = true;
  4732. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4733. }
  4734. }
  4735. // A ref cast must not remove the constness
  4736. if( isConst )
  4737. ctx->type.dataType.MakeHandleToConst(true);
  4738. }
  4739. return conversionDone;
  4740. }
  4741. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4742. {
  4743. asCDataType to = toOrig;
  4744. to.MakeReference(false);
  4745. asASSERT( !ctx->type.dataType.IsReference() );
  4746. // Maybe no conversion is needed
  4747. if( to.IsEqualExceptConst(ctx->type.dataType) )
  4748. {
  4749. // A primitive is const or not
  4750. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4751. return asCC_NO_CONV;
  4752. }
  4753. // Is the conversion an ambiguous enum value?
  4754. if( ctx->enumValue != "" )
  4755. {
  4756. if( to.IsEnumType() )
  4757. {
  4758. // Attempt to resolve an ambiguous enum value
  4759. asCDataType out;
  4760. asDWORD value;
  4761. if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) )
  4762. {
  4763. ctx->type.SetConstantDW(out, value);
  4764. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4765. // Reset the enum value since we no longer need it
  4766. ctx->enumValue = "";
  4767. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  4768. return asCC_NO_CONV;
  4769. }
  4770. }
  4771. // The enum value is ambiguous
  4772. if( node && generateCode )
  4773. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  4774. // Set a dummy to allow the compiler to try to continue the conversion
  4775. ctx->type.SetDummy();
  4776. }
  4777. // Determine the cost of this conversion
  4778. asUINT cost = asCC_NO_CONV;
  4779. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4780. cost = asCC_INT_FLOAT_CONV;
  4781. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
  4782. cost = asCC_INT_FLOAT_CONV;
  4783. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  4784. cost = asCC_SIGNED_CONV;
  4785. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  4786. cost = asCC_SIGNED_CONV;
  4787. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  4788. cost = asCC_PRIMITIVE_SIZE_CONV;
  4789. // Start by implicitly converting constant values
  4790. if( ctx->type.isConstant )
  4791. {
  4792. ImplicitConversionConstant(ctx, to, node, convType);
  4793. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4794. return cost;
  4795. }
  4796. // Allow implicit conversion between numbers
  4797. if( generateCode )
  4798. {
  4799. // When generating the code the decision has already been made, so we don't bother determining the cost
  4800. // Convert smaller types to 32bit first
  4801. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  4802. if( s < 4 )
  4803. {
  4804. ConvertToTempVariable(ctx);
  4805. if( ctx->type.dataType.IsIntegerType() )
  4806. {
  4807. if( s == 1 )
  4808. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  4809. else if( s == 2 )
  4810. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  4811. ctx->type.dataType.SetTokenType(ttInt);
  4812. }
  4813. else if( ctx->type.dataType.IsUnsignedType() )
  4814. {
  4815. if( s == 1 )
  4816. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  4817. else if( s == 2 )
  4818. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  4819. ctx->type.dataType.SetTokenType(ttUInt);
  4820. }
  4821. }
  4822. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  4823. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4824. {
  4825. if( ctx->type.dataType.IsIntegerType() ||
  4826. ctx->type.dataType.IsUnsignedType() )
  4827. {
  4828. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4829. {
  4830. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4831. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4832. }
  4833. else
  4834. {
  4835. ConvertToTempVariable(ctx);
  4836. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4837. int offset = AllocateVariable(to, true);
  4838. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4839. ctx->type.SetVariable(to, offset, true);
  4840. }
  4841. }
  4842. else if( ctx->type.dataType.IsFloatType() )
  4843. {
  4844. ConvertToTempVariable(ctx);
  4845. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  4846. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4847. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4848. if( convType != asIC_EXPLICIT_VAL_CAST )
  4849. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4850. }
  4851. else if( ctx->type.dataType.IsDoubleType() )
  4852. {
  4853. ConvertToTempVariable(ctx);
  4854. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4855. int offset = AllocateVariable(to, true);
  4856. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  4857. ctx->type.SetVariable(to, offset, true);
  4858. if( convType != asIC_EXPLICIT_VAL_CAST )
  4859. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4860. }
  4861. // Convert to smaller integer if necessary
  4862. int s = to.GetSizeInMemoryBytes();
  4863. if( s < 4 )
  4864. {
  4865. ConvertToTempVariable(ctx);
  4866. if( s == 1 )
  4867. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4868. else if( s == 2 )
  4869. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4870. }
  4871. }
  4872. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4873. {
  4874. if( ctx->type.dataType.IsIntegerType() ||
  4875. ctx->type.dataType.IsUnsignedType() )
  4876. {
  4877. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4878. {
  4879. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4880. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4881. }
  4882. else
  4883. {
  4884. ConvertToTempVariable(ctx);
  4885. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4886. int offset = AllocateVariable(to, true);
  4887. if( ctx->type.dataType.IsUnsignedType() )
  4888. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4889. else
  4890. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4891. ctx->type.SetVariable(to, offset, true);
  4892. }
  4893. }
  4894. else if( ctx->type.dataType.IsFloatType() )
  4895. {
  4896. ConvertToTempVariable(ctx);
  4897. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4898. int offset = AllocateVariable(to, true);
  4899. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  4900. ctx->type.SetVariable(to, offset, true);
  4901. if( convType != asIC_EXPLICIT_VAL_CAST )
  4902. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4903. }
  4904. else if( ctx->type.dataType.IsDoubleType() )
  4905. {
  4906. ConvertToTempVariable(ctx);
  4907. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  4908. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4909. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4910. if( convType != asIC_EXPLICIT_VAL_CAST )
  4911. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4912. }
  4913. }
  4914. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4915. {
  4916. if( ctx->type.dataType.IsIntegerType() ||
  4917. ctx->type.dataType.IsUnsignedType() )
  4918. {
  4919. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4920. {
  4921. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4922. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4923. }
  4924. else
  4925. {
  4926. ConvertToTempVariable(ctx);
  4927. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4928. int offset = AllocateVariable(to, true);
  4929. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4930. ctx->type.SetVariable(to, offset, true);
  4931. }
  4932. }
  4933. else if( ctx->type.dataType.IsFloatType() )
  4934. {
  4935. ConvertToTempVariable(ctx);
  4936. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  4937. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4938. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4939. if( convType != asIC_EXPLICIT_VAL_CAST )
  4940. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4941. }
  4942. else if( ctx->type.dataType.IsDoubleType() )
  4943. {
  4944. ConvertToTempVariable(ctx);
  4945. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4946. int offset = AllocateVariable(to, true);
  4947. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  4948. ctx->type.SetVariable(to, offset, true);
  4949. if( convType != asIC_EXPLICIT_VAL_CAST )
  4950. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4951. }
  4952. // Convert to smaller integer if necessary
  4953. int s = to.GetSizeInMemoryBytes();
  4954. if( s < 4 )
  4955. {
  4956. ConvertToTempVariable(ctx);
  4957. if( s == 1 )
  4958. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4959. else if( s == 2 )
  4960. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4961. }
  4962. }
  4963. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4964. {
  4965. if( ctx->type.dataType.IsIntegerType() ||
  4966. ctx->type.dataType.IsUnsignedType() )
  4967. {
  4968. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4969. {
  4970. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4971. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4972. }
  4973. else
  4974. {
  4975. ConvertToTempVariable(ctx);
  4976. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4977. int offset = AllocateVariable(to, true);
  4978. if( ctx->type.dataType.IsUnsignedType() )
  4979. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4980. else
  4981. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4982. ctx->type.SetVariable(to, offset, true);
  4983. }
  4984. }
  4985. else if( ctx->type.dataType.IsFloatType() )
  4986. {
  4987. ConvertToTempVariable(ctx);
  4988. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4989. int offset = AllocateVariable(to, true);
  4990. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  4991. ctx->type.SetVariable(to, offset, true);
  4992. if( convType != asIC_EXPLICIT_VAL_CAST )
  4993. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4994. }
  4995. else if( ctx->type.dataType.IsDoubleType() )
  4996. {
  4997. ConvertToTempVariable(ctx);
  4998. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  4999. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5000. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5001. if( convType != asIC_EXPLICIT_VAL_CAST )
  5002. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5003. }
  5004. }
  5005. else if( to.IsFloatType() )
  5006. {
  5007. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5008. {
  5009. ConvertToTempVariable(ctx);
  5010. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5011. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5012. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5013. }
  5014. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5015. {
  5016. ConvertToTempVariable(ctx);
  5017. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5018. int offset = AllocateVariable(to, true);
  5019. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5020. ctx->type.SetVariable(to, offset, true);
  5021. }
  5022. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5023. {
  5024. ConvertToTempVariable(ctx);
  5025. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5026. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5027. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5028. }
  5029. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5030. {
  5031. ConvertToTempVariable(ctx);
  5032. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5033. int offset = AllocateVariable(to, true);
  5034. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5035. ctx->type.SetVariable(to, offset, true);
  5036. }
  5037. else if( ctx->type.dataType.IsDoubleType() )
  5038. {
  5039. ConvertToTempVariable(ctx);
  5040. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5041. int offset = AllocateVariable(to, true);
  5042. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5043. ctx->type.SetVariable(to, offset, true);
  5044. }
  5045. }
  5046. else if( to.IsDoubleType() )
  5047. {
  5048. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5049. {
  5050. ConvertToTempVariable(ctx);
  5051. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5052. int offset = AllocateVariable(to, true);
  5053. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5054. ctx->type.SetVariable(to, offset, true);
  5055. }
  5056. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5057. {
  5058. ConvertToTempVariable(ctx);
  5059. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5060. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5061. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5062. }
  5063. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5064. {
  5065. ConvertToTempVariable(ctx);
  5066. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5067. int offset = AllocateVariable(to, true);
  5068. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5069. ctx->type.SetVariable(to, offset, true);
  5070. }
  5071. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5072. {
  5073. ConvertToTempVariable(ctx);
  5074. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5075. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5076. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5077. }
  5078. else if( ctx->type.dataType.IsFloatType() )
  5079. {
  5080. ConvertToTempVariable(ctx);
  5081. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5082. int offset = AllocateVariable(to, true);
  5083. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5084. ctx->type.SetVariable(to, offset, true);
  5085. }
  5086. }
  5087. }
  5088. else
  5089. {
  5090. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5091. to.IsFloatType() || to.IsDoubleType() ||
  5092. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5093. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5094. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5095. {
  5096. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5097. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5098. }
  5099. }
  5100. // Primitive types on the stack, can be const or non-const
  5101. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5102. return cost;
  5103. }
  5104. asUINT asCCompiler::ImplicitConvLambdaToFunc(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5105. {
  5106. asASSERT( to.GetFuncDef() && ctx->IsLambda() );
  5107. // Check that the lambda has the correct amount of arguments
  5108. asUINT count = 0;
  5109. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5110. while( argNode->nodeType == snIdentifier )
  5111. {
  5112. count++;
  5113. argNode = argNode->next;
  5114. }
  5115. asASSERT( argNode->nodeType == snStatementBlock );
  5116. asCScriptFunction *funcDef = to.GetFuncDef();
  5117. if( funcDef->parameterTypes.GetLength() != count )
  5118. return asCC_NO_CONV;
  5119. // The Lambda can be used as this funcdef
  5120. ctx->type.dataType = to;
  5121. if( generateCode )
  5122. {
  5123. // Build a unique name for the anonymous function
  5124. asCString name;
  5125. if( m_globalVar )
  5126. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5127. else
  5128. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5129. // Register the lambda with the builder for later compilation
  5130. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace);
  5131. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5132. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5133. // Clear the expression node as it is no longer valid
  5134. ctx->exprNode = 0;
  5135. }
  5136. return asCC_CONST_CONV;
  5137. }
  5138. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5139. {
  5140. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5141. ctx->type.dataType.IsNullHandle() );
  5142. if( to.GetFuncDef() && ctx->IsLambda() )
  5143. {
  5144. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5145. }
  5146. // No conversion from void to any other type
  5147. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5148. return asCC_NO_CONV;
  5149. // No conversion from class method to any type (it requires delegate)
  5150. if( ctx->IsClassMethod() )
  5151. return asCC_NO_CONV;
  5152. // Do we want a var type?
  5153. if( to.GetTokenType() == ttQuestion )
  5154. {
  5155. // Any type can be converted to a var type, but only when not generating code
  5156. asASSERT( !generateCode );
  5157. ctx->type.dataType = to;
  5158. return asCC_VARIABLE_CONV;
  5159. }
  5160. // Do we want a primitive?
  5161. else if( to.IsPrimitive() )
  5162. {
  5163. if( !ctx->type.dataType.IsPrimitive() )
  5164. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5165. else
  5166. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5167. }
  5168. else // The target is a complex type
  5169. {
  5170. if( ctx->type.dataType.IsPrimitive() )
  5171. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5172. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  5173. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5174. }
  5175. return asCC_NO_CONV;
  5176. }
  5177. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5178. {
  5179. if( ctx->type.isExplicitHandle )
  5180. {
  5181. // An explicit handle cannot be converted to a primitive
  5182. if( convType != asIC_IMPLICIT_CONV && node )
  5183. {
  5184. asCString str;
  5185. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5186. Error(str, node);
  5187. }
  5188. return asCC_NO_CONV;
  5189. }
  5190. // TODO: Must use the const cast behaviour if the object is read-only
  5191. // Find matching value cast behaviours
  5192. // Here we're only interested in those that convert the type to a primitive type
  5193. asCArray<int> funcs;
  5194. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  5195. if( ot == 0 )
  5196. {
  5197. if( convType != asIC_IMPLICIT_CONV && node )
  5198. {
  5199. asCString str;
  5200. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5201. Error(str, node);
  5202. }
  5203. return asCC_NO_CONV;
  5204. }
  5205. if( convType == asIC_EXPLICIT_VAL_CAST )
  5206. {
  5207. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5208. {
  5209. // accept both implicit and explicit cast
  5210. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5211. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5212. mthd->parameterTypes.GetLength() == 0 &&
  5213. mthd->returnType.IsPrimitive() )
  5214. funcs.PushLast(ot->methods[n]);
  5215. }
  5216. }
  5217. else
  5218. {
  5219. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5220. {
  5221. // accept only implicit cast
  5222. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5223. if( mthd->name == "opImplConv" &&
  5224. mthd->parameterTypes.GetLength() == 0 &&
  5225. mthd->returnType.IsPrimitive() )
  5226. funcs.PushLast(ot->methods[n]);
  5227. }
  5228. }
  5229. int funcId = 0;
  5230. if( to.IsMathType() )
  5231. {
  5232. // This matrix describes the priorities of the types to search for, for each target type
  5233. // The first column is the target type, the priorities goes from left to right
  5234. eTokenType matchMtx[10][10] =
  5235. {
  5236. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5237. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5238. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5239. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5240. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5241. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5242. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5243. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5244. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5245. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5246. };
  5247. // Which row to use?
  5248. eTokenType *row = 0;
  5249. for( unsigned int type = 0; type < 10; type++ )
  5250. {
  5251. if( to.GetTokenType() == matchMtx[type][0] )
  5252. {
  5253. row = &matchMtx[type][0];
  5254. break;
  5255. }
  5256. }
  5257. // Find the best matching cast operator
  5258. if( row )
  5259. {
  5260. asCDataType target(to);
  5261. // Priority goes from left to right in the matrix
  5262. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5263. {
  5264. target.SetTokenType(row[attempt]);
  5265. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5266. {
  5267. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5268. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5269. {
  5270. funcId = funcs[n];
  5271. break;
  5272. }
  5273. }
  5274. }
  5275. }
  5276. }
  5277. else
  5278. {
  5279. // Only accept the exact conversion for non-math types
  5280. // Find the matching cast operator
  5281. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5282. {
  5283. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5284. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5285. {
  5286. funcId = funcs[n];
  5287. break;
  5288. }
  5289. }
  5290. }
  5291. // Did we find a suitable function?
  5292. if( funcId != 0 )
  5293. {
  5294. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5295. if( generateCode )
  5296. {
  5297. Dereference(ctx, true);
  5298. PerformFunctionCall(funcId, ctx);
  5299. }
  5300. else
  5301. ctx->type.Set(descr->returnType);
  5302. // Allow one more implicit conversion to another primitive type
  5303. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5304. }
  5305. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5306. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5307. funcs.SetLength(0);
  5308. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5309. {
  5310. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5311. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5312. func->name == "opImplConv" )
  5313. {
  5314. // Does the operator take the ?&out parameter?
  5315. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5316. func->parameterTypes.GetLength() != 1 ||
  5317. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5318. func->inOutFlags[0] != asTM_OUTREF )
  5319. continue;
  5320. funcs.PushLast(ot->methods[n]);
  5321. }
  5322. }
  5323. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5324. asASSERT( funcs.GetLength() <= 1 );
  5325. if( funcs.GetLength() == 1 )
  5326. {
  5327. if( generateCode )
  5328. {
  5329. // Allocate a temporary variable of the requested type
  5330. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5331. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5332. // Pass the reference of that variable to the function as output parameter
  5333. asCDataType toRef(to);
  5334. toRef.MakeReference(true);
  5335. toRef.MakeReadOnly(false);
  5336. asCArray<asSExprContext *> args;
  5337. asSExprContext arg(engine);
  5338. // Don't mark the variable as temporary, so it won't be freed too early
  5339. arg.type.SetVariable(toRef, stackOffset, false);
  5340. arg.type.isLValue = true;
  5341. arg.exprNode = node;
  5342. args.PushLast(&arg);
  5343. // Call the behaviour method
  5344. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  5345. // Use the reference to the variable as the result of the expression
  5346. // Now we can mark the variable as temporary
  5347. toRef.MakeReference(false);
  5348. ctx->type.SetVariable(toRef, stackOffset, true);
  5349. }
  5350. else
  5351. ctx->type.Set(to);
  5352. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5353. }
  5354. if( convType != asIC_IMPLICIT_CONV && node )
  5355. {
  5356. asCString str;
  5357. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5358. Error(str, node);
  5359. }
  5360. return asCC_NO_CONV;
  5361. }
  5362. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5363. {
  5364. // Convert null to any object type handle, but not to a non-handle type
  5365. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5366. {
  5367. if( to.IsObjectHandle() )
  5368. {
  5369. ctx->type.dataType = to;
  5370. return asCC_REF_CONV;
  5371. }
  5372. return asCC_NO_CONV;
  5373. }
  5374. asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
  5375. // First attempt to convert the base type without instantiating another instance
  5376. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
  5377. {
  5378. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5379. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  5380. {
  5381. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5382. return asCC_REF_CONV;
  5383. }
  5384. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5385. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  5386. {
  5387. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5388. return asCC_REF_CONV;
  5389. }
  5390. // If the types are not equal yet, then we may still be able to find a reference cast
  5391. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  5392. {
  5393. // We may still be able to find an implicit ref cast behaviour
  5394. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5395. // Was the conversion done?
  5396. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  5397. return asCC_REF_CONV;
  5398. }
  5399. }
  5400. // Convert matching function types
  5401. if( to.GetFuncDef() )
  5402. {
  5403. // If the input expression is already a funcdef, check if it can be converted
  5404. if( ctx->type.dataType.GetFuncDef() &&
  5405. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  5406. {
  5407. asCScriptFunction *toFunc = to.GetFuncDef();
  5408. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  5409. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5410. {
  5411. ctx->type.dataType.SetFuncDef(toFunc);
  5412. return asCC_REF_CONV;
  5413. }
  5414. }
  5415. // If the input expression is a deferred function ref, check if there is a matching func
  5416. if( ctx->methodName != "" )
  5417. {
  5418. // Determine the namespace
  5419. asSNameSpace *ns = 0;
  5420. asCString name = "";
  5421. int pos = ctx->methodName.FindLast("::");
  5422. if( pos >= 0 )
  5423. {
  5424. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5425. // Trim off the last ::
  5426. if( nsName.GetLength() > 2 )
  5427. nsName.SetLength(nsName.GetLength()-2);
  5428. ns = DetermineNameSpace(nsName);
  5429. name = ctx->methodName.SubString(pos+2);
  5430. }
  5431. else
  5432. {
  5433. DetermineNameSpace("");
  5434. name = ctx->methodName;
  5435. }
  5436. asCArray<int> funcs;
  5437. if( ns )
  5438. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5439. // Check if any of the functions have perfect match
  5440. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5441. {
  5442. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5443. if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
  5444. {
  5445. if( generateCode )
  5446. {
  5447. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5448. // Make sure the identified function is shared if we're compiling a shared function
  5449. if( !func->IsShared() && outFunc->IsShared() )
  5450. {
  5451. asCString msg;
  5452. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5453. Error(msg, node);
  5454. }
  5455. }
  5456. ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
  5457. return asCC_REF_CONV;
  5458. }
  5459. }
  5460. }
  5461. }
  5462. return asCC_NO_CONV;
  5463. }
  5464. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5465. {
  5466. asUINT cost = asCC_NO_CONV;
  5467. // If the base type is still different, and we are allowed to instance
  5468. // another object then we can try an implicit value cast
  5469. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  5470. {
  5471. // TODO: Implement support for implicit constructor/factory
  5472. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  5473. if( ot == 0 )
  5474. return cost;
  5475. asCArray<int> funcs;
  5476. if( convType == asIC_EXPLICIT_VAL_CAST )
  5477. {
  5478. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5479. {
  5480. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5481. // accept both implicit and explicit cast
  5482. if( (func->name == "opConv" ||
  5483. func->name == "opImplConv") &&
  5484. func->returnType.GetObjectType() == to.GetObjectType() &&
  5485. func->parameterTypes.GetLength() == 0 )
  5486. funcs.PushLast(ot->methods[n]);
  5487. }
  5488. }
  5489. else
  5490. {
  5491. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5492. {
  5493. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5494. // accept only implicit cast
  5495. if( func->name == "opImplConv" &&
  5496. func->returnType.GetObjectType() == to.GetObjectType() &&
  5497. func->parameterTypes.GetLength() == 0 )
  5498. funcs.PushLast(ot->methods[n]);
  5499. }
  5500. }
  5501. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5502. asASSERT( funcs.GetLength() <= 1 );
  5503. if( funcs.GetLength() == 1 )
  5504. {
  5505. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5506. if( generateCode )
  5507. {
  5508. Dereference(ctx, true);
  5509. bool useVariable = false;
  5510. int stackOffset = 0;
  5511. if( f->DoesReturnOnStack() )
  5512. {
  5513. useVariable = true;
  5514. stackOffset = AllocateVariable(f->returnType, true);
  5515. // Push the pointer to the pre-allocated space for the return value
  5516. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5517. // The object pointer is already on the stack, but should be the top
  5518. // one, so we need to swap the pointers in order to get the correct
  5519. ctx->bc.Instr(asBC_SwapPtr);
  5520. }
  5521. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5522. }
  5523. else
  5524. ctx->type.Set(f->returnType);
  5525. cost = asCC_TO_OBJECT_CONV;
  5526. }
  5527. else
  5528. {
  5529. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5530. // Look for a value cast with variable type
  5531. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5532. {
  5533. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5534. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5535. func->name == "opImplConv" )
  5536. {
  5537. // Does the operator take the ?&out parameter?
  5538. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5539. func->parameterTypes.GetLength() != 1 ||
  5540. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5541. func->inOutFlags[0] != asTM_OUTREF )
  5542. continue;
  5543. funcs.PushLast(ot->methods[n]);
  5544. }
  5545. }
  5546. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5547. asASSERT( funcs.GetLength() <= 1 );
  5548. if( funcs.GetLength() == 1 )
  5549. {
  5550. cost = asCC_TO_OBJECT_CONV;
  5551. if( generateCode )
  5552. {
  5553. // Allocate a temporary variable of the requested type
  5554. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5555. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5556. // Pass the reference of that variable to the function as output parameter
  5557. asCDataType toRef(to);
  5558. toRef.MakeReference(false);
  5559. asSExprContext arg(engine);
  5560. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5561. // If this an object on the heap, the pointer must be dereferenced
  5562. if( IsVariableOnHeap(stackOffset) )
  5563. arg.bc.Instr(asBC_RDSPtr);
  5564. // Don't mark the variable as temporary, so it won't be freed too early
  5565. arg.type.SetVariable(toRef, stackOffset, false);
  5566. arg.type.isLValue = true;
  5567. arg.exprNode = node;
  5568. // Mark the argument as clean, so that MakeFunctionCall knows it
  5569. // doesn't have to make a copy of it in order to protect the value
  5570. arg.isCleanArg = true;
  5571. // Call the behaviour method
  5572. asCArray<asSExprContext *> args;
  5573. args.PushLast(&arg);
  5574. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  5575. // Use the reference to the variable as the result of the expression
  5576. // Now we can mark the variable as temporary
  5577. ctx->type.SetVariable(toRef, stackOffset, true);
  5578. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5579. }
  5580. else
  5581. {
  5582. // All casts are legal
  5583. ctx->type.Set(to);
  5584. }
  5585. }
  5586. }
  5587. }
  5588. return cost;
  5589. }
  5590. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5591. {
  5592. // First try a ref cast
  5593. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  5594. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  5595. // construct the object through any of the available constructors
  5596. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  5597. {
  5598. asCArray<int> funcs;
  5599. funcs = to.GetObjectType()->beh.constructors;
  5600. asCArray<asSExprContext *> args;
  5601. args.PushLast(ctx);
  5602. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  5603. // Did we find a matching constructor?
  5604. if( funcs.GetLength() == 1 )
  5605. {
  5606. if( generateCode )
  5607. {
  5608. // If the ASHANDLE receives a variable type parameter, then we need to
  5609. // make sure the expression is treated as a handle and not as a value
  5610. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  5611. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  5612. {
  5613. if( !ctx->type.isExplicitHandle )
  5614. {
  5615. asCDataType toHandle = ctx->type.dataType;
  5616. toHandle.MakeHandle(true);
  5617. toHandle.MakeReference(true);
  5618. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  5619. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  5620. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5621. }
  5622. ctx->type.isExplicitHandle = true;
  5623. }
  5624. // TODO: This should really reuse the code from CompileConstructCall
  5625. // Allocate the new object
  5626. asCTypeInfo tempObj;
  5627. tempObj.dataType = to;
  5628. tempObj.dataType.MakeReference(false);
  5629. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  5630. tempObj.dataType.MakeReference(true);
  5631. tempObj.isTemporary = true;
  5632. tempObj.isVariable = true;
  5633. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5634. // Push the address of the object on the stack
  5635. asSExprContext e(engine);
  5636. if( onHeap )
  5637. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5638. PrepareFunctionCall(funcs[0], &e.bc, args);
  5639. MoveArgsToStack(funcs[0], &e.bc, args, false);
  5640. // If the object is allocated on the stack, then call the constructor as a normal function
  5641. if( onHeap )
  5642. {
  5643. int offset = 0;
  5644. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5645. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  5646. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5647. }
  5648. else
  5649. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5650. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  5651. // Add tag that the object has been initialized
  5652. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  5653. // The constructor doesn't return anything,
  5654. // so we have to manually inform the type of
  5655. // the return value
  5656. e.type = tempObj;
  5657. if( !onHeap )
  5658. e.type.dataType.MakeReference(false);
  5659. // Push the address of the object on the stack again
  5660. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5661. MergeExprBytecodeAndType(ctx, &e);
  5662. }
  5663. else
  5664. {
  5665. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  5666. }
  5667. }
  5668. }
  5669. // If the base type is still different, and we are allowed to instance
  5670. // another object then we can try an implicit value cast
  5671. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  5672. {
  5673. // Attempt implicit value cast
  5674. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  5675. }
  5676. // If we still haven't converted the base type to the correct type, then there is
  5677. // no need to continue as it is not possible to do the conversion
  5678. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  5679. return asCC_NO_CONV;
  5680. if( to.IsObjectHandle() )
  5681. {
  5682. // There is no extra cost in converting to a handle
  5683. // reference to handle -> handle
  5684. // reference -> handle
  5685. // object -> handle
  5686. // handle -> reference to handle
  5687. // reference -> reference to handle
  5688. // object -> reference to handle
  5689. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  5690. // If the rvalue is a handle to a const object, then
  5691. // the lvalue must also be a handle to a const object
  5692. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  5693. {
  5694. if( convType != asIC_IMPLICIT_CONV )
  5695. {
  5696. asASSERT(node);
  5697. asCString str;
  5698. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5699. Error(str, node);
  5700. }
  5701. }
  5702. if( !ctx->type.dataType.IsObjectHandle() )
  5703. {
  5704. // An object type can be directly converted to a handle of the
  5705. // same type by doing a ref copy to a new variable
  5706. if( ctx->type.dataType.SupportHandles() )
  5707. {
  5708. asCDataType dt = ctx->type.dataType;
  5709. dt.MakeHandle(true);
  5710. dt.MakeReference(false);
  5711. if( generateCode )
  5712. {
  5713. // If the expression is already a local variable, then it is not
  5714. // necessary to do a ref copy, as the ref objects on the stack are
  5715. // really handles, only the handles cannot be modified.
  5716. if( ctx->type.isVariable )
  5717. {
  5718. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  5719. ctx->type.dataType.MakeReadOnly(false);
  5720. ctx->type.dataType.MakeHandle(true);
  5721. ctx->type.dataType.MakeReadOnly(true);
  5722. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  5723. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5724. {
  5725. ctx->bc.Instr(asBC_PopPtr);
  5726. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  5727. ctx->type.dataType.MakeReference(true);
  5728. }
  5729. else if( ctx->type.dataType.IsReference() )
  5730. {
  5731. ctx->bc.Instr(asBC_RDSPtr);
  5732. ctx->type.dataType.MakeReference(false);
  5733. }
  5734. }
  5735. else
  5736. {
  5737. int offset = AllocateVariable(dt, true);
  5738. if( ctx->type.dataType.IsReference() )
  5739. ctx->bc.Instr(asBC_RDSPtr);
  5740. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5741. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  5742. ctx->bc.Instr(asBC_PopPtr);
  5743. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5744. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5745. if( to.IsReference() )
  5746. dt.MakeReference(true);
  5747. else
  5748. ctx->bc.Instr(asBC_RDSPtr);
  5749. ctx->type.SetVariable(dt, offset, true);
  5750. }
  5751. }
  5752. else
  5753. ctx->type.dataType = dt;
  5754. // When this conversion is done the expression is no longer an lvalue
  5755. ctx->type.isLValue = false;
  5756. }
  5757. }
  5758. if( ctx->type.dataType.IsObjectHandle() )
  5759. {
  5760. // A handle to non-const can be converted to a
  5761. // handle to const, but not the other way
  5762. if( to.IsHandleToConst() )
  5763. ctx->type.dataType.MakeHandleToConst(true);
  5764. // A const handle can be converted to a non-const
  5765. // handle and vice versa as the handle is just a value
  5766. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5767. }
  5768. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5769. {
  5770. if( generateCode )
  5771. {
  5772. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5773. // If the input type is a handle, then a simple ref copy is enough
  5774. bool isExplicitHandle = ctx->type.isExplicitHandle;
  5775. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  5776. // If the input type is read-only we'll need to temporarily
  5777. // remove this constness, otherwise the assignment will fail
  5778. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5779. ctx->type.dataType.MakeReadOnly(false);
  5780. // If the object already is a temporary variable, then the copy
  5781. // doesn't have to be made as it is already a unique object
  5782. PrepareTemporaryObject(node, ctx);
  5783. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5784. ctx->type.isExplicitHandle = isExplicitHandle;
  5785. }
  5786. // A non-reference can be converted to a reference,
  5787. // by putting the value in a temporary variable
  5788. ctx->type.dataType.MakeReference(true);
  5789. // Since it is a new temporary variable it doesn't have to be const
  5790. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5791. }
  5792. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  5793. {
  5794. Dereference(ctx, generateCode);
  5795. }
  5796. }
  5797. else // if( !to.IsObjectHandle() )
  5798. {
  5799. if( !to.IsReference() )
  5800. {
  5801. // reference to handle -> object
  5802. // handle -> object
  5803. // reference -> object
  5804. // An implicit handle can be converted to an object by adding a check for null pointer
  5805. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  5806. {
  5807. if( generateCode )
  5808. {
  5809. if( ctx->type.dataType.IsReference() )
  5810. {
  5811. // The pointer on the stack refers to the handle
  5812. ctx->bc.Instr(asBC_ChkRefS);
  5813. }
  5814. else
  5815. {
  5816. // The pointer on the stack refers to the object
  5817. ctx->bc.Instr(asBC_CHKREF);
  5818. }
  5819. }
  5820. ctx->type.dataType.MakeHandle(false);
  5821. }
  5822. // A const object can be converted to a non-const object through a copy
  5823. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  5824. allowObjectConstruct )
  5825. {
  5826. // Does the object type allow a copy to be made?
  5827. if( ctx->type.dataType.CanBeCopied() )
  5828. {
  5829. if( generateCode )
  5830. {
  5831. // Make a temporary object with the copy
  5832. PrepareTemporaryObject(node, ctx);
  5833. }
  5834. // In case the object was already in a temporary variable, then the function
  5835. // didn't really do anything so we need to remove the constness here
  5836. ctx->type.dataType.MakeReadOnly(false);
  5837. // Add the cost for the copy
  5838. cost += asCC_TO_OBJECT_CONV;
  5839. }
  5840. }
  5841. if( ctx->type.dataType.IsReference() )
  5842. {
  5843. // This may look strange, but a value type allocated on the stack is already
  5844. // correct, so nothing should be done other than remove the mark as reference.
  5845. // For types allocated on the heap, it is necessary to dereference the pointer
  5846. // that is currently on the stack
  5847. if( IsVariableOnHeap(ctx->type.stackOffset) )
  5848. Dereference(ctx, generateCode);
  5849. else
  5850. ctx->type.dataType.MakeReference(false);
  5851. }
  5852. // A non-const object can be converted to a const object directly
  5853. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  5854. {
  5855. ctx->type.dataType.MakeReadOnly(true);
  5856. }
  5857. }
  5858. else // if( to.IsReference() )
  5859. {
  5860. // reference to handle -> reference
  5861. // handle -> reference
  5862. // object -> reference
  5863. if( ctx->type.dataType.IsReference() )
  5864. {
  5865. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  5866. {
  5867. // ASHANDLE objects are really value types, so explicit handle can be removed
  5868. ctx->type.isExplicitHandle = false;
  5869. ctx->type.dataType.MakeHandle(false);
  5870. }
  5871. // A reference to a handle can be converted to a reference to an object
  5872. // by first reading the address, then verifying that it is not null
  5873. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  5874. {
  5875. ctx->type.dataType.MakeHandle(false);
  5876. if( generateCode )
  5877. ctx->bc.Instr(asBC_ChkRefS);
  5878. }
  5879. // A reference to a non-const can be converted to a reference to a const
  5880. if( to.IsReadOnly() )
  5881. ctx->type.dataType.MakeReadOnly(true);
  5882. else if( ctx->type.dataType.IsReadOnly() )
  5883. {
  5884. // A reference to a const can be converted to a reference to a
  5885. // non-const by copying the object to a temporary variable
  5886. ctx->type.dataType.MakeReadOnly(false);
  5887. if( generateCode )
  5888. {
  5889. // If the object already is a temporary variable, then the copy
  5890. // doesn't have to be made as it is already a unique object
  5891. PrepareTemporaryObject(node, ctx);
  5892. }
  5893. // Add the cost for the copy
  5894. cost += asCC_TO_OBJECT_CONV;
  5895. }
  5896. }
  5897. else // if( !ctx->type.dataType.IsReference() )
  5898. {
  5899. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  5900. if( ctx->type.dataType.IsObjectHandle() )
  5901. {
  5902. bool readOnly = false;
  5903. if( ctx->type.dataType.IsHandleToConst() )
  5904. readOnly = true;
  5905. if( generateCode )
  5906. {
  5907. if( ctx->type.isVariable )
  5908. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  5909. else
  5910. ctx->bc.Instr(asBC_CHKREF);
  5911. }
  5912. ctx->type.dataType.MakeHandle(false);
  5913. ctx->type.dataType.MakeReference(true);
  5914. // Make sure a handle to const isn't converted to non-const reference
  5915. if( readOnly )
  5916. ctx->type.dataType.MakeReadOnly(true);
  5917. }
  5918. else
  5919. {
  5920. // A value type allocated on the stack is differentiated
  5921. // by it not being a reference. But it can be handled as
  5922. // reference by pushing the pointer on the stack
  5923. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  5924. (ctx->type.isVariable || ctx->type.isTemporary) &&
  5925. !IsVariableOnHeap(ctx->type.stackOffset) )
  5926. {
  5927. // Actually the pointer is already pushed on the stack in
  5928. // CompileVariableAccess, so we don't need to do anything else
  5929. }
  5930. else if( generateCode )
  5931. {
  5932. // A non-reference can be converted to a reference,
  5933. // by putting the value in a temporary variable
  5934. // If the input type is read-only we'll need to temporarily
  5935. // remove this constness, otherwise the assignment will fail
  5936. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5937. ctx->type.dataType.MakeReadOnly(false);
  5938. // If the object already is a temporary variable, then the copy
  5939. // doesn't have to be made as it is already a unique object
  5940. PrepareTemporaryObject(node, ctx);
  5941. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5942. // Add the cost for the copy
  5943. cost += asCC_TO_OBJECT_CONV;
  5944. }
  5945. // This may look strange as the conversion was to make the expression a reference
  5946. // but a value type allocated on the stack is a reference even without the type
  5947. // being marked as such.
  5948. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  5949. }
  5950. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  5951. // Since it is a new temporary variable it doesn't have to be const
  5952. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5953. }
  5954. }
  5955. }
  5956. return cost;
  5957. }
  5958. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  5959. {
  5960. // Reference types currently don't allow implicit conversion from primitive to object
  5961. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  5962. asCObjectType *objType = to.GetObjectType();
  5963. asASSERT( objType );
  5964. if( !objType || (objType->flags & asOBJ_REF) )
  5965. return asCC_NO_CONV;
  5966. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  5967. asCArray<int> funcs;
  5968. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  5969. {
  5970. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  5971. if( func->parameterTypes.GetLength() == 1 &&
  5972. func->parameterTypes[0].IsPrimitive() &&
  5973. !(func->inOutFlags[0] & asTM_OUTREF) )
  5974. {
  5975. funcs.PushLast(func->id);
  5976. }
  5977. }
  5978. if( funcs.GetLength() == 0 )
  5979. return asCC_NO_CONV;
  5980. // Check if it is possible to choose a best match
  5981. asSExprContext arg(engine);
  5982. arg.type = ctx->type;
  5983. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  5984. asCArray<asSExprContext*> args;
  5985. args.PushLast(&arg);
  5986. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  5987. if( funcs.GetLength() != 1 )
  5988. return asCC_NO_CONV;
  5989. if( !generateCode )
  5990. {
  5991. ctx->type.Set(to);
  5992. return cost;
  5993. }
  5994. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  5995. // Clear the type of ctx, as the type is moved to the arg
  5996. ctx->type.SetDummy();
  5997. // Value types and script types are allocated through the constructor
  5998. asCTypeInfo tempObj;
  5999. tempObj.dataType = to;
  6000. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6001. tempObj.dataType.MakeReference(true);
  6002. tempObj.isTemporary = true;
  6003. tempObj.isVariable = true;
  6004. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6005. // Push the address of the object on the stack
  6006. if( onHeap )
  6007. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6008. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6009. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6010. if( !(objType->flags & asOBJ_REF) )
  6011. {
  6012. // If the object is allocated on the stack, then call the constructor as a normal function
  6013. if( onHeap )
  6014. {
  6015. int offset = 0;
  6016. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6017. for( asUINT n = 0; n < args.GetLength(); n++ )
  6018. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6019. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6020. }
  6021. else
  6022. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6023. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  6024. // Add tag that the object has been initialized
  6025. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6026. // The constructor doesn't return anything,
  6027. // so we have to manually inform the type of
  6028. // the return value
  6029. ctx->type = tempObj;
  6030. if( !onHeap )
  6031. ctx->type.dataType.MakeReference(false);
  6032. // Push the address of the object on the stack again
  6033. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6034. }
  6035. else
  6036. {
  6037. asASSERT( objType->flags & asOBJ_SCOPED );
  6038. // Call the factory to create the reference type
  6039. PerformFunctionCall(funcs[0], ctx, false, &args);
  6040. }
  6041. return cost;
  6042. }
  6043. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6044. {
  6045. asASSERT(from->type.isConstant);
  6046. // TODO: node should be the node of the value that is
  6047. // converted (not the operator that provokes the implicit
  6048. // conversion)
  6049. // If the base type is correct there is no more to do
  6050. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6051. // References cannot be constants
  6052. if( from->type.dataType.IsReference() ) return;
  6053. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6054. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6055. {
  6056. if( from->type.dataType.IsFloatType() ||
  6057. from->type.dataType.IsDoubleType() ||
  6058. from->type.dataType.IsUnsignedType() ||
  6059. from->type.dataType.IsIntegerType() )
  6060. {
  6061. // Transform the value
  6062. // Float constants can be implicitly converted to int
  6063. if( from->type.dataType.IsFloatType() )
  6064. {
  6065. float fc = from->type.floatValue;
  6066. int ic = int(fc);
  6067. if( float(ic) != fc )
  6068. {
  6069. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6070. }
  6071. from->type.intValue = ic;
  6072. }
  6073. // Double constants can be implicitly converted to int
  6074. else if( from->type.dataType.IsDoubleType() )
  6075. {
  6076. double fc = from->type.doubleValue;
  6077. int ic = int(fc);
  6078. if( double(ic) != fc )
  6079. {
  6080. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6081. }
  6082. from->type.intValue = ic;
  6083. }
  6084. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6085. {
  6086. // Verify that it is possible to convert to signed without getting negative
  6087. if( from->type.intValue < 0 )
  6088. {
  6089. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6090. }
  6091. // Convert to 32bit
  6092. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6093. from->type.intValue = from->type.byteValue;
  6094. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6095. from->type.intValue = from->type.wordValue;
  6096. }
  6097. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6098. {
  6099. // Convert to 32bit
  6100. from->type.intValue = int(from->type.qwordValue);
  6101. }
  6102. else if( from->type.dataType.IsIntegerType() &&
  6103. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6104. {
  6105. // Convert to 32bit
  6106. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6107. from->type.intValue = (signed char)from->type.byteValue;
  6108. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6109. from->type.intValue = (short)from->type.wordValue;
  6110. }
  6111. // Set the resulting type
  6112. if( to.IsEnumType() )
  6113. from->type.dataType = to;
  6114. else
  6115. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  6116. }
  6117. // Check if a downsize is necessary
  6118. if( to.IsIntegerType() &&
  6119. from->type.dataType.IsIntegerType() &&
  6120. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6121. {
  6122. // Verify if it is possible
  6123. if( to.GetSizeInMemoryBytes() == 1 )
  6124. {
  6125. if( char(from->type.intValue) != from->type.intValue )
  6126. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6127. from->type.byteValue = char(from->type.intValue);
  6128. }
  6129. else if( to.GetSizeInMemoryBytes() == 2 )
  6130. {
  6131. if( short(from->type.intValue) != from->type.intValue )
  6132. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6133. from->type.wordValue = short(from->type.intValue);
  6134. }
  6135. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6136. }
  6137. }
  6138. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6139. {
  6140. // Float constants can be implicitly converted to int
  6141. if( from->type.dataType.IsFloatType() )
  6142. {
  6143. float fc = from->type.floatValue;
  6144. asINT64 ic = asINT64(fc);
  6145. if( float(ic) != fc )
  6146. {
  6147. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6148. }
  6149. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6150. from->type.qwordValue = ic;
  6151. }
  6152. // Double constants can be implicitly converted to int
  6153. else if( from->type.dataType.IsDoubleType() )
  6154. {
  6155. double fc = from->type.doubleValue;
  6156. asINT64 ic = asINT64(fc);
  6157. if( double(ic) != fc )
  6158. {
  6159. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6160. }
  6161. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6162. from->type.qwordValue = ic;
  6163. }
  6164. else if( from->type.dataType.IsUnsignedType() )
  6165. {
  6166. // Convert to 64bit
  6167. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6168. from->type.qwordValue = from->type.byteValue;
  6169. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6170. from->type.qwordValue = from->type.wordValue;
  6171. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6172. from->type.qwordValue = from->type.dwordValue;
  6173. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6174. {
  6175. if( asINT64(from->type.qwordValue) < 0 )
  6176. {
  6177. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6178. }
  6179. }
  6180. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6181. }
  6182. else if( from->type.dataType.IsIntegerType() )
  6183. {
  6184. // Convert to 64bit
  6185. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6186. from->type.qwordValue = (signed char)from->type.byteValue;
  6187. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6188. from->type.qwordValue = (short)from->type.wordValue;
  6189. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6190. from->type.qwordValue = from->type.intValue;
  6191. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6192. }
  6193. }
  6194. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6195. {
  6196. if( from->type.dataType.IsFloatType() )
  6197. {
  6198. float fc = from->type.floatValue;
  6199. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6200. // To maintain a consistent behaviour across compilers we convert to int first.
  6201. asUINT uic = asUINT(int(fc));
  6202. if( float(uic) != fc )
  6203. {
  6204. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6205. }
  6206. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  6207. from->type.intValue = uic;
  6208. // Try once more, in case of a smaller type
  6209. ImplicitConversionConstant(from, to, node, convType);
  6210. }
  6211. else if( from->type.dataType.IsDoubleType() )
  6212. {
  6213. double fc = from->type.doubleValue;
  6214. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6215. // To maintain a consistent behaviour across compilers we convert to int first.
  6216. asUINT uic = asUINT(int(fc));
  6217. if( double(uic) != fc )
  6218. {
  6219. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6220. }
  6221. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  6222. from->type.intValue = uic;
  6223. // Try once more, in case of a smaller type
  6224. ImplicitConversionConstant(from, to, node, convType);
  6225. }
  6226. else if( from->type.dataType.IsIntegerType() )
  6227. {
  6228. // Verify that it is possible to convert to unsigned without loosing negative
  6229. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) ||
  6230. (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) )
  6231. {
  6232. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6233. }
  6234. // Check if any data is lost
  6235. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF )
  6236. {
  6237. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6238. }
  6239. // Convert to 32bit
  6240. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6241. from->type.intValue = (signed char)from->type.byteValue;
  6242. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6243. from->type.intValue = (short)from->type.wordValue;
  6244. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  6245. // Try once more, in case of a smaller type
  6246. ImplicitConversionConstant(from, to, node, convType);
  6247. }
  6248. else if( from->type.dataType.IsUnsignedType() &&
  6249. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6250. {
  6251. // Convert to 32bit
  6252. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6253. from->type.dwordValue = from->type.byteValue;
  6254. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6255. from->type.dwordValue = from->type.wordValue;
  6256. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  6257. // Try once more, in case of a smaller type
  6258. ImplicitConversionConstant(from, to, node, convType);
  6259. }
  6260. else if( from->type.dataType.IsUnsignedType() &&
  6261. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6262. {
  6263. // Verify if it is possible
  6264. if( to.GetSizeInMemoryBytes() == 1 )
  6265. {
  6266. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  6267. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6268. from->type.byteValue = asBYTE(from->type.dwordValue);
  6269. }
  6270. else if( to.GetSizeInMemoryBytes() == 2 )
  6271. {
  6272. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  6273. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6274. from->type.wordValue = asWORD(from->type.dwordValue);
  6275. }
  6276. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6277. }
  6278. }
  6279. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6280. {
  6281. if( from->type.dataType.IsFloatType() )
  6282. {
  6283. float fc = from->type.floatValue;
  6284. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6285. asQWORD uic = asQWORD(asINT64(fc));
  6286. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6287. // MSVC6 doesn't support this conversion
  6288. if( float(uic) != fc )
  6289. {
  6290. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6291. }
  6292. #endif
  6293. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6294. from->type.qwordValue = uic;
  6295. }
  6296. else if( from->type.dataType.IsDoubleType() )
  6297. {
  6298. double fc = from->type.doubleValue;
  6299. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6300. asQWORD uic = asQWORD(asINT64(fc));
  6301. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6302. // MSVC6 doesn't support this conversion
  6303. if( double(uic) != fc )
  6304. {
  6305. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6306. }
  6307. #endif
  6308. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6309. from->type.qwordValue = uic;
  6310. }
  6311. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6312. {
  6313. // Convert to 64bit
  6314. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6315. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  6316. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6317. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  6318. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6319. from->type.qwordValue = (asINT64)from->type.intValue;
  6320. // Verify that it is possible to convert to unsigned without loosing negative
  6321. if( asINT64(from->type.qwordValue) < 0 )
  6322. {
  6323. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6324. }
  6325. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6326. }
  6327. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6328. {
  6329. // Verify that it is possible to convert to unsigned without loosing negative
  6330. if( asINT64(from->type.qwordValue) < 0 )
  6331. {
  6332. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6333. }
  6334. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6335. }
  6336. else if( from->type.dataType.IsUnsignedType() )
  6337. {
  6338. // Convert to 64bit
  6339. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6340. from->type.qwordValue = from->type.byteValue;
  6341. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6342. from->type.qwordValue = from->type.wordValue;
  6343. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6344. from->type.qwordValue = from->type.dwordValue;
  6345. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6346. }
  6347. }
  6348. else if( to.IsFloatType() )
  6349. {
  6350. if( from->type.dataType.IsDoubleType() )
  6351. {
  6352. double ic = from->type.doubleValue;
  6353. float fc = float(ic);
  6354. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6355. from->type.floatValue = fc;
  6356. }
  6357. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6358. {
  6359. // Must properly convert value in case the from value is smaller
  6360. int ic;
  6361. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6362. ic = (signed char)from->type.byteValue;
  6363. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6364. ic = (short)from->type.wordValue;
  6365. else
  6366. ic = from->type.intValue;
  6367. float fc = float(ic);
  6368. if( int(fc) != ic )
  6369. {
  6370. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6371. }
  6372. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6373. from->type.floatValue = fc;
  6374. }
  6375. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6376. {
  6377. float fc = float(asINT64(from->type.qwordValue));
  6378. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  6379. {
  6380. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6381. }
  6382. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6383. from->type.floatValue = fc;
  6384. }
  6385. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6386. {
  6387. // Must properly convert value in case the from value is smaller
  6388. unsigned int uic;
  6389. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6390. uic = from->type.byteValue;
  6391. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6392. uic = from->type.wordValue;
  6393. else
  6394. uic = from->type.dwordValue;
  6395. float fc = float(uic);
  6396. if( (unsigned int)(fc) != uic )
  6397. {
  6398. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6399. }
  6400. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6401. from->type.floatValue = fc;
  6402. }
  6403. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6404. {
  6405. float fc = float((asINT64)from->type.qwordValue);
  6406. if( asQWORD(fc) != from->type.qwordValue )
  6407. {
  6408. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6409. }
  6410. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6411. from->type.floatValue = fc;
  6412. }
  6413. }
  6414. else if( to.IsDoubleType() )
  6415. {
  6416. if( from->type.dataType.IsFloatType() )
  6417. {
  6418. float ic = from->type.floatValue;
  6419. double fc = double(ic);
  6420. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6421. from->type.doubleValue = fc;
  6422. }
  6423. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6424. {
  6425. // Must properly convert value in case the from value is smaller
  6426. int ic;
  6427. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6428. ic = (signed char)from->type.byteValue;
  6429. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6430. ic = (short)from->type.wordValue;
  6431. else
  6432. ic = from->type.intValue;
  6433. double fc = double(ic);
  6434. if( int(fc) != ic )
  6435. {
  6436. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6437. }
  6438. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6439. from->type.doubleValue = fc;
  6440. }
  6441. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6442. {
  6443. double fc = double(asINT64(from->type.qwordValue));
  6444. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  6445. {
  6446. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6447. }
  6448. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6449. from->type.doubleValue = fc;
  6450. }
  6451. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6452. {
  6453. // Must properly convert value in case the from value is smaller
  6454. unsigned int uic;
  6455. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6456. uic = from->type.byteValue;
  6457. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6458. uic = from->type.wordValue;
  6459. else
  6460. uic = from->type.dwordValue;
  6461. double fc = double(uic);
  6462. if( (unsigned int)(fc) != uic )
  6463. {
  6464. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6465. }
  6466. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6467. from->type.doubleValue = fc;
  6468. }
  6469. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6470. {
  6471. double fc = double((asINT64)from->type.qwordValue);
  6472. if( asQWORD(fc) != from->type.qwordValue )
  6473. {
  6474. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6475. }
  6476. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6477. from->type.doubleValue = fc;
  6478. }
  6479. }
  6480. }
  6481. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  6482. {
  6483. // Don't allow any operators on expressions that take address of class method
  6484. // If methodName is set but the type is not an object, then it is a global function
  6485. if( lctx->methodName != "" || rctx->IsClassMethod() )
  6486. {
  6487. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  6488. return -1;
  6489. }
  6490. // Implicit handle types should always be treated as handles in assignments
  6491. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6492. {
  6493. lctx->type.dataType.MakeHandle(true);
  6494. lctx->type.isExplicitHandle = true;
  6495. }
  6496. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  6497. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  6498. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  6499. !lctx->type.dataType.GetBehaviour()->copy)
  6500. lctx->type.isExplicitHandle = true;
  6501. // If the left hand expression is a property accessor, then that should be used
  6502. // to do the assignment instead of the ordinary operator. The exception is when
  6503. // the property accessor is for a handle property, and the operation is a value
  6504. // assignment.
  6505. if( (lctx->property_get || lctx->property_set) &&
  6506. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  6507. {
  6508. if( op != ttAssignment )
  6509. {
  6510. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  6511. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  6512. }
  6513. // It is not allowed to do a handle assignment on a property
  6514. // accessor that doesn't take a handle in the set accessor.
  6515. if( lctx->property_set && lctx->type.isExplicitHandle )
  6516. {
  6517. // set_opIndex has 2 arguments, where as normal setters have only 1
  6518. asCArray<asCDataType>& parameterTypes =
  6519. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  6520. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  6521. {
  6522. // Process the property to free the memory
  6523. ProcessPropertySetAccessor(lctx, rctx, opNode);
  6524. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  6525. return -1;
  6526. }
  6527. }
  6528. MergeExprBytecodeAndType(ctx, lctx);
  6529. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  6530. }
  6531. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6532. {
  6533. // Get the handle to the object that will be used for the value assignment
  6534. ProcessPropertyGetAccessor(lctx, opNode);
  6535. }
  6536. if( lctx->type.dataType.IsPrimitive() )
  6537. {
  6538. if( !lctx->type.isLValue )
  6539. {
  6540. Error(TXT_NOT_LVALUE, lexpr);
  6541. return -1;
  6542. }
  6543. if( op != ttAssignment )
  6544. {
  6545. // Compute the operator before the assignment
  6546. asCTypeInfo lvalue = lctx->type;
  6547. if( lctx->type.isTemporary && !lctx->type.isVariable )
  6548. {
  6549. // The temporary variable must not be freed until the
  6550. // assignment has been performed. lvalue still holds
  6551. // the information about the temporary variable
  6552. lctx->type.isTemporary = false;
  6553. }
  6554. asSExprContext o(engine);
  6555. CompileOperator(opNode, lctx, rctx, &o);
  6556. MergeExprBytecode(rctx, &o);
  6557. rctx->type = o.type;
  6558. // Convert the rvalue to the right type and validate it
  6559. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  6560. MergeExprBytecode(ctx, rctx);
  6561. lctx->type = lvalue;
  6562. // The lvalue continues the same, either it was a variable, or a reference in the register
  6563. }
  6564. else
  6565. {
  6566. // Convert the rvalue to the right type and validate it
  6567. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  6568. MergeExprBytecode(ctx, rctx);
  6569. MergeExprBytecode(ctx, lctx);
  6570. }
  6571. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6572. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6573. ctx->type = lctx->type;
  6574. }
  6575. else if( lctx->type.isExplicitHandle )
  6576. {
  6577. if( !lctx->type.isLValue )
  6578. {
  6579. Error(TXT_NOT_LVALUE, lexpr);
  6580. return -1;
  6581. }
  6582. // Object handles don't have any compound assignment operators
  6583. if( op != ttAssignment )
  6584. {
  6585. asCString str;
  6586. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6587. Error(str, lexpr);
  6588. return -1;
  6589. }
  6590. if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  6591. {
  6592. // The object is a value type but that should be treated as a handle
  6593. // Make sure the right hand value is a handle
  6594. if( !rctx->type.isExplicitHandle &&
  6595. !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  6596. {
  6597. // Function names can be considered handles already
  6598. if( rctx->methodName == "" )
  6599. {
  6600. asCDataType dt = rctx->type.dataType;
  6601. dt.MakeHandle(true);
  6602. dt.MakeReference(false);
  6603. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  6604. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6605. {
  6606. asCString str;
  6607. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6608. Error(str, rexpr);
  6609. return -1;
  6610. }
  6611. }
  6612. }
  6613. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx, true) )
  6614. {
  6615. // An overloaded assignment operator was found (or a compilation error occured)
  6616. return 0;
  6617. }
  6618. // The object must implement the opAssign method
  6619. asCString msg;
  6620. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6621. Error(msg.AddressOf(), opNode);
  6622. return -1;
  6623. }
  6624. else
  6625. {
  6626. asCDataType dt = lctx->type.dataType;
  6627. dt.MakeReference(false);
  6628. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
  6629. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6630. {
  6631. asCString str;
  6632. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6633. Error(str, rexpr);
  6634. return -1;
  6635. }
  6636. MergeExprBytecode(ctx, rctx);
  6637. MergeExprBytecode(ctx, lctx);
  6638. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6639. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6640. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6641. ctx->type = lctx->type;
  6642. // After the handle assignment the original handle is left on the stack
  6643. ctx->type.dataType.MakeReference(false);
  6644. }
  6645. }
  6646. else // if( lctx->type.dataType.IsObject() )
  6647. {
  6648. // The lvalue reference may be marked as a temporary, if for example
  6649. // it was originated as a handle returned from a function. In such
  6650. // cases it must be possible to assign values to it anyway.
  6651. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6652. {
  6653. // Convert the handle to a object reference
  6654. asCDataType to;
  6655. to = lctx->type.dataType;
  6656. to.MakeHandle(false);
  6657. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  6658. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  6659. }
  6660. // Check for overloaded assignment operator
  6661. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  6662. {
  6663. // An overloaded assignment operator was found (or a compilation error occured)
  6664. return 0;
  6665. }
  6666. // No registered operator was found. In case the operation is a direct
  6667. // assignment and the rvalue is the same type as the lvalue, then we can
  6668. // still use the byte-for-byte copy to do the assignment
  6669. if( op != ttAssignment )
  6670. {
  6671. asCString str;
  6672. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6673. Error(str, lexpr);
  6674. return -1;
  6675. }
  6676. // If the left hand expression is simple, i.e. without any
  6677. // function calls or allocations of memory, then we can avoid
  6678. // doing a copy of the right hand expression (done by PrepareArgument).
  6679. // Instead the reference to the value can be placed directly on the
  6680. // stack.
  6681. //
  6682. // This optimization should only be done for value types, where
  6683. // the application developer is responsible for making the
  6684. // implementation safe against unwanted destruction of the input
  6685. // reference before the time.
  6686. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  6687. // Implicitly convert the rvalue to the type of the lvalue
  6688. bool needConversion = false;
  6689. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6690. needConversion = true;
  6691. if( !simpleExpr || needConversion )
  6692. {
  6693. asCDataType dt = lctx->type.dataType;
  6694. dt.MakeReference(true);
  6695. dt.MakeReadOnly(true);
  6696. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  6697. if( r < 0 )
  6698. return -1;
  6699. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6700. {
  6701. asCString str;
  6702. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6703. Error(str, rexpr);
  6704. return -1;
  6705. }
  6706. }
  6707. else
  6708. {
  6709. // Process any property accessor first, before placing the final reference on the stack
  6710. ProcessPropertyGetAccessor(rctx, rexpr);
  6711. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  6712. rctx->bc.Instr(asBC_RDSPtr);
  6713. }
  6714. MergeExprBytecode(ctx, rctx);
  6715. MergeExprBytecode(ctx, lctx);
  6716. if( !simpleExpr || needConversion )
  6717. {
  6718. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  6719. {
  6720. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  6721. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  6722. // as the value allocated on the stack is guaranteed to be safe.
  6723. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  6724. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  6725. else
  6726. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6727. }
  6728. }
  6729. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6730. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6731. ctx->type = lctx->type;
  6732. }
  6733. return 0;
  6734. }
  6735. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  6736. {
  6737. asCScriptNode *lexpr = expr->firstChild;
  6738. if( lexpr->next )
  6739. {
  6740. // Compile the two expression terms
  6741. asSExprContext lctx(engine), rctx(engine);
  6742. int rr = CompileAssignment(lexpr->next->next, &rctx);
  6743. int lr = CompileCondition(lexpr, &lctx);
  6744. if( lr >= 0 && rr >= 0 )
  6745. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  6746. // Since the operands failed, the assignment was not computed
  6747. ctx->type.SetDummy();
  6748. return -1;
  6749. }
  6750. return CompileCondition(lexpr, ctx);
  6751. }
  6752. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  6753. {
  6754. asCTypeInfo ctype;
  6755. // Compile the conditional expression
  6756. asCScriptNode *cexpr = expr->firstChild;
  6757. if( cexpr->next )
  6758. {
  6759. //-------------------------------
  6760. // Compile the condition
  6761. asSExprContext e(engine);
  6762. int r = CompileExpression(cexpr, &e);
  6763. if( r < 0 )
  6764. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6765. // Allow value types to be converted to bool using 'bool opImplConv()'
  6766. if( e.type.dataType.GetObjectType() && (e.type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  6767. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  6768. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6769. {
  6770. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  6771. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6772. }
  6773. ctype = e.type;
  6774. ProcessPropertyGetAccessor(&e, cexpr);
  6775. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  6776. ProcessDeferredParams(&e);
  6777. //-------------------------------
  6778. // Compile the left expression
  6779. asSExprContext le(engine);
  6780. int lr = CompileAssignment(cexpr->next, &le);
  6781. //-------------------------------
  6782. // Compile the right expression
  6783. asSExprContext re(engine);
  6784. int rr = CompileAssignment(cexpr->next->next, &re);
  6785. if( lr >= 0 && rr >= 0 )
  6786. {
  6787. // Don't allow any operators on expressions that take address of class method
  6788. if( le.IsClassMethod() || re.IsClassMethod() )
  6789. {
  6790. Error(TXT_INVALID_OP_ON_METHOD, expr);
  6791. return -1;
  6792. }
  6793. ProcessPropertyGetAccessor(&le, cexpr->next);
  6794. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  6795. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  6796. // Allow a 0 or null in the first case to be implicitly converted to the second type
  6797. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsIntegerType() )
  6798. {
  6799. asCDataType to = re.type.dataType;
  6800. to.MakeReference(false);
  6801. to.MakeReadOnly(true);
  6802. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6803. }
  6804. else if( le.type.IsNullConstant() )
  6805. {
  6806. asCDataType to = re.type.dataType;
  6807. to.MakeHandle(true);
  6808. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6809. }
  6810. // Allow either case to be converted to const @ if the other is const @
  6811. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  6812. {
  6813. le.type.dataType.MakeHandleToConst(true);
  6814. re.type.dataType.MakeHandleToConst(true);
  6815. }
  6816. //---------------------------------
  6817. // Output the byte code
  6818. int afterLabel = nextLabel++;
  6819. int elseLabel = nextLabel++;
  6820. // If left expression is void, then we don't need to store the result
  6821. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  6822. {
  6823. // Put the code for the condition expression on the output
  6824. MergeExprBytecode(ctx, &e);
  6825. // Added the branch decision
  6826. ctx->type = e.type;
  6827. ConvertToVariable(ctx);
  6828. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6829. ctx->bc.Instr(asBC_ClrHi);
  6830. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6831. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6832. // Add the left expression
  6833. MergeExprBytecode(ctx, &le);
  6834. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6835. // Add the right expression
  6836. ctx->bc.Label((short)elseLabel);
  6837. MergeExprBytecode(ctx, &re);
  6838. ctx->bc.Label((short)afterLabel);
  6839. // Make sure both expressions have the same type
  6840. if( le.type.dataType != re.type.dataType )
  6841. Error(TXT_BOTH_MUST_BE_SAME, expr);
  6842. // Set the type of the result
  6843. ctx->type = le.type;
  6844. }
  6845. else
  6846. {
  6847. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  6848. //
  6849. // Restrictions for the condition to be used as lvalue:
  6850. // 1. both b and c must be of the same type and be lvalue references
  6851. // 2. neither of the expressions can have any deferred arguments
  6852. // that would have to be cleaned up after the reference
  6853. // 3. neither expression can be temporary
  6854. //
  6855. // If either expression is local, the resulting lvalue is not valid
  6856. // for return since it is not allowed to return references to local
  6857. // variables.
  6858. //
  6859. // The reference to the local variable must be loaded into the register,
  6860. // the resulting expression must not be considered as a local variable
  6861. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  6862. if( le.type.isLValue && re.type.isLValue &&
  6863. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 &&
  6864. !le.type.isTemporary && !re.type.isTemporary &&
  6865. le.type.dataType == re.type.dataType )
  6866. {
  6867. // Put the code for the condition expression on the output
  6868. MergeExprBytecode(ctx, &e);
  6869. // Add the branch decision
  6870. ctx->type = e.type;
  6871. ConvertToVariable(ctx);
  6872. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6873. ctx->bc.Instr(asBC_ClrHi);
  6874. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6875. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6876. // Start of the left expression
  6877. MergeExprBytecode(ctx, &le);
  6878. if( !le.type.dataType.IsReference() && le.type.isVariable )
  6879. {
  6880. // Load the address of the variable into the register
  6881. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  6882. }
  6883. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6884. // Start of the right expression
  6885. ctx->bc.Label((short)elseLabel);
  6886. MergeExprBytecode(ctx, &re);
  6887. if( !re.type.dataType.IsReference() && re.type.isVariable )
  6888. {
  6889. // Load the address of the variable into the register
  6890. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  6891. }
  6892. ctx->bc.Label((short)afterLabel);
  6893. // In case the options were to objects, it is necessary to dereference the pointer on
  6894. // the stack so it will point to the actual object, instead of the variable
  6895. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  6896. {
  6897. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  6898. ctx->bc.Instr(asBC_RDSPtr);
  6899. }
  6900. // The result is an lvalue
  6901. ctx->type.isLValue = true;
  6902. ctx->type.dataType = le.type.dataType;
  6903. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  6904. ctx->type.dataType.MakeReference(true);
  6905. else
  6906. ctx->type.dataType.MakeReference(false);
  6907. // It can't be a treated as a variable, since we don't know which one was used
  6908. ctx->type.isVariable = false;
  6909. ctx->type.isTemporary = false;
  6910. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  6911. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  6912. }
  6913. else
  6914. {
  6915. // Allocate temporary variable and copy the result to that one
  6916. asCTypeInfo temp;
  6917. temp = le.type;
  6918. temp.dataType.MakeReference(false);
  6919. temp.dataType.MakeReadOnly(false);
  6920. // Make sure the variable isn't used in any of the expressions,
  6921. // as it would be overwritten which may cause crashes or less visible bugs
  6922. int l = int(reservedVariables.GetLength());
  6923. e.bc.GetVarsUsed(reservedVariables);
  6924. le.bc.GetVarsUsed(reservedVariables);
  6925. re.bc.GetVarsUsed(reservedVariables);
  6926. int offset = AllocateVariable(temp.dataType, true, false);
  6927. reservedVariables.SetLength(l);
  6928. temp.SetVariable(temp.dataType, offset, true);
  6929. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  6930. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  6931. // Put the code for the condition expression on the output
  6932. MergeExprBytecode(ctx, &e);
  6933. // Add the branch decision
  6934. ctx->type = e.type;
  6935. ConvertToVariable(ctx);
  6936. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6937. ctx->bc.Instr(asBC_ClrHi);
  6938. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6939. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6940. // Assign the result of the left expression to the temporary variable
  6941. asCTypeInfo rtemp;
  6942. rtemp = temp;
  6943. if( rtemp.dataType.IsObjectHandle() )
  6944. rtemp.isExplicitHandle = true;
  6945. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  6946. MergeExprBytecode(ctx, &le);
  6947. if( !rtemp.dataType.IsPrimitive() )
  6948. {
  6949. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6950. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  6951. }
  6952. asCTypeInfo result;
  6953. result = rtemp;
  6954. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  6955. if( !result.dataType.IsPrimitive() )
  6956. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  6957. // Release the old temporary variable
  6958. ReleaseTemporaryVariable(le.type, &ctx->bc);
  6959. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6960. // Start of the right expression
  6961. ctx->bc.Label((short)elseLabel);
  6962. // Copy the result to the same temporary variable
  6963. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  6964. MergeExprBytecode(ctx, &re);
  6965. if( !rtemp.dataType.IsPrimitive() )
  6966. {
  6967. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6968. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  6969. }
  6970. result = rtemp;
  6971. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  6972. if( !result.dataType.IsPrimitive() )
  6973. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  6974. // Release the old temporary variable
  6975. ReleaseTemporaryVariable(re.type, &ctx->bc);
  6976. ctx->bc.Label((short)afterLabel);
  6977. // Make sure both expressions have the same type
  6978. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  6979. Error(TXT_BOTH_MUST_BE_SAME, expr);
  6980. // Set the temporary variable as output
  6981. ctx->type = rtemp;
  6982. ctx->type.isExplicitHandle = isExplicitHandle;
  6983. if( !ctx->type.dataType.IsPrimitive() )
  6984. {
  6985. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6986. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  6987. }
  6988. // Make sure the output isn't marked as being a literal constant
  6989. ctx->type.isConstant = false;
  6990. }
  6991. }
  6992. }
  6993. else
  6994. {
  6995. ctx->type.SetDummy();
  6996. return -1;
  6997. }
  6998. }
  6999. else
  7000. return CompileExpression(cexpr, ctx);
  7001. return 0;
  7002. }
  7003. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  7004. {
  7005. asASSERT(expr->nodeType == snExpression);
  7006. // Check if this is an initialization of a temp object with an initialization list
  7007. if( expr->firstChild && expr->firstChild->nodeType == snDataType )
  7008. {
  7009. // TODO: It should be possible to infer the type of the object from where the
  7010. // expression will be used. The compilation of the initialization list
  7011. // should be deferred until it is known for what it will be used. It will
  7012. // then for example be possible to write expressions like:
  7013. //
  7014. // @dict = {{'key', 'value'}};
  7015. // funcTakingArrayOfInt({1,2,3,4});
  7016. // Determine the type of the temporary object
  7017. asCDataType dt = builder->CreateDataTypeFromNode(expr->firstChild, script, outFunc->nameSpace);
  7018. // Do not allow constructing non-shared types in shared functions
  7019. if( outFunc->IsShared() &&
  7020. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  7021. {
  7022. asCString msg;
  7023. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  7024. Error(msg, expr);
  7025. }
  7026. // Allocate and initialize the temporary object
  7027. int offset = AllocateVariable(dt, true);
  7028. CompileInitialization(expr->lastChild, &ctx->bc, dt, expr, offset, 0, 0);
  7029. // Push the reference to the object on the stack
  7030. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7031. ctx->type.SetVariable(dt, offset, true);
  7032. ctx->type.isLValue = false;
  7033. // If the variable is allocated on the heap we have a reference,
  7034. // otherwise the actual object pointer is pushed on the stack.
  7035. if( IsVariableOnHeap(offset) )
  7036. ctx->type.dataType.MakeReference(true);
  7037. return 0;
  7038. }
  7039. // Convert to polish post fix, i.e: a+b => ab+
  7040. asCArray<asCScriptNode *> postfix;
  7041. ConvertToPostFix(expr, postfix);
  7042. // Compile the postfix formatted expression
  7043. return CompilePostFixExpression(&postfix, ctx);
  7044. }
  7045. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7046. {
  7047. // The algorithm that I've implemented here is similar to
  7048. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7049. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7050. // Count the nodes in order to preallocate the buffers
  7051. int count = 0;
  7052. asCScriptNode *node = expr->firstChild;
  7053. while( node )
  7054. {
  7055. count++;
  7056. node = node->next;
  7057. }
  7058. asCArray<asCScriptNode *> stackA(count);
  7059. asCArray<asCScriptNode *> &stackB = postfix;
  7060. stackB.Allocate(count, false);
  7061. node = expr->firstChild;
  7062. while( node )
  7063. {
  7064. int precedence = GetPrecedence(node);
  7065. while( stackA.GetLength() > 0 &&
  7066. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7067. stackB.PushLast(stackA.PopLast());
  7068. stackA.PushLast(node);
  7069. node = node->next;
  7070. }
  7071. while( stackA.GetLength() > 0 )
  7072. stackB.PushLast(stackA.PopLast());
  7073. }
  7074. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  7075. {
  7076. // Shouldn't send any byte code
  7077. asASSERT(ctx->bc.GetLastInstr() == -1);
  7078. // Set the context to a dummy type to avoid further
  7079. // errors in case the expression fails to compile
  7080. ctx->type.SetDummy();
  7081. // Evaluate the operands and operators
  7082. asCArray<asSExprContext*> free;
  7083. asCArray<asSExprContext*> expr;
  7084. int ret = 0;
  7085. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7086. {
  7087. asCScriptNode *node = (*postfix)[n];
  7088. if( node->nodeType == snExprTerm )
  7089. {
  7090. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  7091. expr.PushLast(e);
  7092. e->exprNode = node;
  7093. ret = CompileExpressionTerm(node, e);
  7094. }
  7095. else
  7096. {
  7097. asSExprContext *r = expr.PopLast();
  7098. asSExprContext *l = expr.PopLast();
  7099. // Now compile the operator
  7100. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  7101. ret = CompileOperator(node, l, r, e);
  7102. expr.PushLast(e);
  7103. // Free the operands
  7104. l->Clear();
  7105. free.PushLast(l);
  7106. r->Clear();
  7107. free.PushLast(r);
  7108. }
  7109. }
  7110. if( ret == 0 )
  7111. {
  7112. asASSERT(expr.GetLength() == 1);
  7113. // The final result should be moved to the output context
  7114. MergeExprBytecodeAndType(ctx, expr[0]);
  7115. }
  7116. // Clean up
  7117. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7118. asDELETE(expr[e], asSExprContext);
  7119. for( asUINT f = 0; f < free.GetLength(); f++ )
  7120. asDELETE(free[f], asSExprContext);
  7121. return ret;
  7122. }
  7123. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  7124. {
  7125. // Shouldn't send any byte code
  7126. asASSERT(ctx->bc.GetLastInstr() == -1);
  7127. // Set the type as a dummy by default, in case of any compiler errors
  7128. ctx->type.SetDummy();
  7129. // Compile the value node
  7130. asCScriptNode *vnode = node->firstChild;
  7131. while( vnode->nodeType != snExprValue )
  7132. vnode = vnode->next;
  7133. asSExprContext v(engine);
  7134. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  7135. // Compile post fix operators
  7136. asCScriptNode *pnode = vnode->next;
  7137. while( pnode )
  7138. {
  7139. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  7140. pnode = pnode->next;
  7141. }
  7142. // Compile pre fix operators
  7143. pnode = vnode->prev;
  7144. while( pnode )
  7145. {
  7146. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  7147. pnode = pnode->prev;
  7148. }
  7149. // Return the byte code and final type description
  7150. MergeExprBytecodeAndType(ctx, &v);
  7151. return 0;
  7152. }
  7153. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  7154. {
  7155. bool found = false;
  7156. // It is a local variable or parameter?
  7157. // This is not accessible by default arg expressions
  7158. sVariable *v = 0;
  7159. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  7160. v = variables->GetVariable(name.AddressOf());
  7161. if( v )
  7162. {
  7163. found = true;
  7164. if( v->isPureConstant )
  7165. ctx->type.SetConstantQW(v->type, v->constantValue);
  7166. else if( v->type.IsPrimitive() )
  7167. {
  7168. if( v->type.IsReference() )
  7169. {
  7170. // Copy the reference into the register
  7171. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  7172. ctx->bc.Instr(asBC_PopRPtr);
  7173. ctx->type.Set(v->type);
  7174. }
  7175. else
  7176. ctx->type.SetVariable(v->type, v->stackOffset, false);
  7177. ctx->type.isLValue = true;
  7178. }
  7179. else
  7180. {
  7181. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  7182. ctx->type.SetVariable(v->type, v->stackOffset, false);
  7183. // If the variable is allocated on the heap we have a reference,
  7184. // otherwise the actual object pointer is pushed on the stack.
  7185. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  7186. // Implicitly dereference handle parameters sent by reference
  7187. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  7188. ctx->bc.Instr(asBC_RDSPtr);
  7189. ctx->type.isLValue = true;
  7190. }
  7191. }
  7192. // Is it a class member?
  7193. // This is not accessible by default arg expressions
  7194. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  7195. {
  7196. if( name == THIS_TOKEN && !objType )
  7197. {
  7198. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  7199. // The object pointer is located at stack position 0
  7200. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7201. ctx->type.SetVariable(dt, 0, false);
  7202. ctx->type.dataType.MakeReference(true);
  7203. ctx->type.isLValue = true;
  7204. found = true;
  7205. }
  7206. if( !found )
  7207. {
  7208. // See if there are any matching property accessors
  7209. asSExprContext access(engine);
  7210. if( objType )
  7211. access.type.Set(asCDataType::CreateObject(objType, false));
  7212. else
  7213. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  7214. access.type.dataType.MakeReference(true);
  7215. int r = 0;
  7216. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  7217. {
  7218. // This is an index access, check if there is a property accessor that takes an index arg
  7219. asSExprContext dummyArg(engine);
  7220. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  7221. }
  7222. if( r == 0 )
  7223. {
  7224. // Normal property access
  7225. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  7226. }
  7227. if( r < 0 ) return -1;
  7228. if( access.property_get || access.property_set )
  7229. {
  7230. if( !objType )
  7231. {
  7232. // Prepare the bytecode for the member access
  7233. // This is only done when accessing through the implicit this pointer
  7234. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7235. }
  7236. MergeExprBytecodeAndType(ctx, &access);
  7237. found = true;
  7238. }
  7239. }
  7240. if( !found )
  7241. {
  7242. asCDataType dt;
  7243. if( objType )
  7244. dt = asCDataType::CreateObject(objType, false);
  7245. else
  7246. dt = asCDataType::CreateObject(outFunc->objectType, false);
  7247. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7248. if( prop )
  7249. {
  7250. // Is the property access allowed?
  7251. if( prop->isPrivate && prop->isInherited )
  7252. {
  7253. if( engine->ep.privatePropAsProtected )
  7254. {
  7255. // The application is allowing inherited classes to access private properties of the parent
  7256. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  7257. // as it was how the compiler behaved earlier.
  7258. asCString msg;
  7259. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  7260. Warning(msg, errNode);
  7261. }
  7262. else
  7263. {
  7264. asCString msg;
  7265. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  7266. Error(msg, errNode);
  7267. }
  7268. }
  7269. if( !objType )
  7270. {
  7271. // The object pointer is located at stack position 0
  7272. // This is only done when accessing through the implicit this pointer
  7273. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7274. ctx->type.SetVariable(dt, 0, false);
  7275. ctx->type.dataType.MakeReference(true);
  7276. Dereference(ctx, true);
  7277. }
  7278. // TODO: This is the same as what is in CompileExpressionPostOp
  7279. // Put the offset on the stack
  7280. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  7281. if( prop->type.IsReference() )
  7282. ctx->bc.Instr(asBC_RDSPtr);
  7283. // Reference to primitive must be stored in the temp register
  7284. if( prop->type.IsPrimitive() )
  7285. {
  7286. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  7287. ctx->bc.Instr(asBC_PopRPtr);
  7288. }
  7289. // Set the new type (keeping info about temp variable)
  7290. ctx->type.dataType = prop->type;
  7291. ctx->type.dataType.MakeReference(true);
  7292. ctx->type.isVariable = false;
  7293. ctx->type.isLValue = true;
  7294. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7295. {
  7296. // Objects that are members are not references
  7297. ctx->type.dataType.MakeReference(false);
  7298. }
  7299. // If the object reference is const, the property will also be const
  7300. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  7301. found = true;
  7302. }
  7303. else if( outFunc->objectType )
  7304. {
  7305. // If it is not a property, it may still be the name of a method which can be used to create delegates
  7306. asCObjectType *ot = outFunc->objectType;
  7307. asCScriptFunction *func = 0;
  7308. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7309. {
  7310. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7311. if( f->name == name &&
  7312. (builder->module->accessMask & f->accessMask) )
  7313. {
  7314. func = f;
  7315. break;
  7316. }
  7317. }
  7318. if( func )
  7319. {
  7320. // An object method was found. Keep the name of the method in the expression, but
  7321. // don't actually modify the bytecode at this point since it is not yet known what
  7322. // the method will be used for, or even what overloaded method should be used.
  7323. ctx->methodName = name;
  7324. // Place the object pointer on the stack, as if the expression was this.func
  7325. if( !objType )
  7326. {
  7327. // The object pointer is located at stack position 0
  7328. // This is only done when accessing through the implicit this pointer
  7329. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7330. ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
  7331. ctx->type.dataType.MakeReference(true);
  7332. Dereference(ctx, true);
  7333. }
  7334. found = true;
  7335. }
  7336. }
  7337. }
  7338. }
  7339. // Recursively search parent namespaces for global entities
  7340. asCString currScope = scope;
  7341. // Get the namespace for this scope. This may return null if the scope is an enum
  7342. asSNameSpace *ns = DetermineNameSpace(currScope);
  7343. if( ns && currScope != "::" )
  7344. currScope = ns->name;
  7345. while( !found && !noGlobal && !objType )
  7346. {
  7347. // Is it a global property?
  7348. if( !found && ns )
  7349. {
  7350. // See if there are any matching global property accessors
  7351. asSExprContext access(engine);
  7352. int r = 0;
  7353. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  7354. {
  7355. // This is an index access, check if there is a property accessor that takes an index arg
  7356. asSExprContext dummyArg(engine);
  7357. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  7358. }
  7359. if( r == 0 )
  7360. {
  7361. // Normal property access
  7362. r = FindPropertyAccessor(name, &access, errNode, ns);
  7363. }
  7364. if( r < 0 ) return -1;
  7365. if( access.property_get || access.property_set )
  7366. {
  7367. // Prepare the bytecode for the function call
  7368. MergeExprBytecodeAndType(ctx, &access);
  7369. found = true;
  7370. }
  7371. // See if there is any matching global property
  7372. if( !found )
  7373. {
  7374. bool isCompiled = true;
  7375. bool isPureConstant = false;
  7376. bool isAppProp = false;
  7377. asQWORD constantValue = 0;
  7378. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  7379. if( prop )
  7380. {
  7381. found = true;
  7382. // Verify that the global property has been compiled already
  7383. if( isCompiled )
  7384. {
  7385. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  7386. {
  7387. ctx->type.dataType.MakeHandle(true);
  7388. ctx->type.isExplicitHandle = true;
  7389. }
  7390. // If the global property is a pure constant
  7391. // we can allow the compiler to optimize it. Pure
  7392. // constants are global constant variables that were
  7393. // initialized by literal constants.
  7394. if( isPureConstant )
  7395. ctx->type.SetConstantQW(prop->type, constantValue);
  7396. else
  7397. {
  7398. // A shared type must not access global vars, unless they
  7399. // too are shared, e.g. application registered vars
  7400. if( outFunc->IsShared() )
  7401. {
  7402. if( !isAppProp )
  7403. {
  7404. asCString str;
  7405. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  7406. Error(str, errNode);
  7407. // Allow the compilation to continue to catch other problems
  7408. }
  7409. }
  7410. ctx->type.Set(prop->type);
  7411. ctx->type.isLValue = true;
  7412. if( ctx->type.dataType.IsPrimitive() )
  7413. {
  7414. // Load the address of the variable into the register
  7415. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  7416. ctx->type.dataType.MakeReference(true);
  7417. }
  7418. else
  7419. {
  7420. // Push the address of the variable on the stack
  7421. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  7422. // If the object is a value type or a non-handle variable to a reference type,
  7423. // then we must validate the existance as it could potentially be accessed
  7424. // before it is initialized.
  7425. // This check is not needed for application registered properties, since they
  7426. // are guaranteed to be valid by the application itself.
  7427. if( !isAppProp &&
  7428. ((ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  7429. !ctx->type.dataType.IsObjectHandle()) )
  7430. {
  7431. ctx->bc.Instr(asBC_ChkRefS);
  7432. }
  7433. // If the address pushed on the stack is to a value type or an object
  7434. // handle, then mark the expression as a reference. Addresses to a reference
  7435. // type aren't marked as references to get correct behaviour
  7436. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  7437. ctx->type.dataType.IsObjectHandle() )
  7438. {
  7439. ctx->type.dataType.MakeReference(true);
  7440. }
  7441. else
  7442. {
  7443. asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  7444. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  7445. ctx->bc.Instr(asBC_RDSPtr);
  7446. }
  7447. }
  7448. }
  7449. }
  7450. else
  7451. {
  7452. asCString str;
  7453. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  7454. Error(str, errNode);
  7455. return -1;
  7456. }
  7457. }
  7458. }
  7459. }
  7460. // Is it the name of a global function?
  7461. if( !noFunction && !found && ns )
  7462. {
  7463. asCArray<int> funcs;
  7464. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7465. if( funcs.GetLength() > 0 )
  7466. {
  7467. found = true;
  7468. // Defer the evaluation of which function until it is actually used
  7469. // Store the namespace and name of the function for later
  7470. ctx->type.SetUndefinedFuncHandle(engine);
  7471. ctx->methodName = ns ? ns->name + "::" + name : name;
  7472. }
  7473. }
  7474. // Is it an enum value?
  7475. if( !found )
  7476. {
  7477. // The enum type may be declared in a namespace too
  7478. asCObjectType *scopeType = 0;
  7479. if( currScope != "" && currScope != "::" )
  7480. {
  7481. // Use the last scope name as the enum type
  7482. asCString enumType = currScope;
  7483. asCString nsScope;
  7484. int p = currScope.FindLast("::");
  7485. if( p != -1 )
  7486. {
  7487. enumType = currScope.SubString(p+2);
  7488. nsScope = currScope.SubString(0, p);
  7489. }
  7490. asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
  7491. if( ns )
  7492. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  7493. }
  7494. asDWORD value = 0;
  7495. asCDataType dt;
  7496. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  7497. {
  7498. // scoped enum value found
  7499. found = true;
  7500. }
  7501. else if( !engine->ep.requireEnumScope )
  7502. {
  7503. // Look for the enum value without explicitly informing the enum type
  7504. asSNameSpace *ns = DetermineNameSpace(currScope);
  7505. int e = 0;
  7506. if( ns )
  7507. e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  7508. if( e )
  7509. {
  7510. found = true;
  7511. if( e == 2 )
  7512. {
  7513. // Ambiguous enum value: Save the name for resolution later.
  7514. // The ambiguity could be resolved now, but I hesitate
  7515. // to store too much information in the context.
  7516. ctx->enumValue = name.AddressOf();
  7517. // We cannot set a dummy value because it will pass through
  7518. // cleanly as an integer.
  7519. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  7520. return 0;
  7521. }
  7522. }
  7523. }
  7524. if( found )
  7525. {
  7526. // Even if the enum type is not shared, and we're compiling a shared object,
  7527. // the use of the values are still allowed, since they are treated as constants.
  7528. // an enum value was resolved
  7529. ctx->type.SetConstantDW(dt, value);
  7530. }
  7531. else
  7532. {
  7533. // If nothing was found because the scope doesn't match a namespace or an enum
  7534. // then this should be reported as an error and the search interrupted
  7535. if( !ns && !scopeType )
  7536. {
  7537. ctx->type.SetDummy();
  7538. asCString str;
  7539. str.Format(TXT_UNKNOWN_SCOPE_s, scope.AddressOf());
  7540. Error(str, errNode);
  7541. return -1;
  7542. }
  7543. }
  7544. }
  7545. if( !found )
  7546. {
  7547. if( currScope == "" || currScope == "::" )
  7548. break;
  7549. // Move up to parent namespace
  7550. int pos = currScope.FindLast("::");
  7551. if( pos >= 0 )
  7552. currScope = currScope.SubString(0, pos);
  7553. else
  7554. currScope = "::";
  7555. if( ns )
  7556. ns = engine->GetParentNameSpace(ns);
  7557. }
  7558. }
  7559. // The name doesn't match any variable
  7560. if( !found )
  7561. {
  7562. // Give dummy value
  7563. ctx->type.SetDummy();
  7564. if( !isOptional )
  7565. {
  7566. // Prepend the scope to the name for the error message
  7567. asCString ename;
  7568. if( scope != "" && scope != "::" )
  7569. ename = scope + "::";
  7570. else
  7571. ename = scope;
  7572. ename += name;
  7573. asCString str;
  7574. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  7575. Error(str, errNode);
  7576. // Declare the variable now so that it will not be reported again
  7577. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  7578. // Mark the variable as initialized so that the user will not be bother by it again
  7579. sVariable *v = variables->GetVariable(name.AddressOf());
  7580. asASSERT(v);
  7581. if( v ) v->isInitialized = true;
  7582. }
  7583. // Return -1 to signal that the variable wasn't found
  7584. return -1;
  7585. }
  7586. return 0;
  7587. }
  7588. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  7589. {
  7590. // Shouldn't receive any byte code
  7591. asASSERT(ctx->bc.GetLastInstr() == -1);
  7592. asCScriptNode *vnode = node->firstChild;
  7593. ctx->exprNode = vnode;
  7594. if( vnode->nodeType == snVariableAccess )
  7595. {
  7596. // Determine the scope resolution of the variable
  7597. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  7598. // Determine the name of the variable
  7599. asASSERT(vnode->nodeType == snIdentifier );
  7600. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  7601. return CompileVariableAccess(name, scope, ctx, node);
  7602. }
  7603. else if( vnode->nodeType == snConstant )
  7604. {
  7605. if( vnode->tokenType == ttIntConstant )
  7606. {
  7607. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7608. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  7609. // Do we need 64 bits?
  7610. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  7611. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  7612. if( val>>31 )
  7613. {
  7614. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  7615. if( val>>63 )
  7616. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7617. else
  7618. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  7619. }
  7620. else
  7621. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  7622. }
  7623. else if( vnode->tokenType == ttBitsConstant )
  7624. {
  7625. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7626. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  7627. // TODO: Check for overflow
  7628. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
  7629. // Do we need 64 bits?
  7630. if( val>>32 )
  7631. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7632. else
  7633. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  7634. }
  7635. else if( vnode->tokenType == ttFloatConstant )
  7636. {
  7637. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7638. // TODO: Check for overflow
  7639. size_t numScanned;
  7640. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  7641. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  7642. #ifndef AS_USE_DOUBLE_AS_FLOAT
  7643. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  7644. asASSERT(numScanned == vnode->tokenLength - 1);
  7645. #endif
  7646. }
  7647. else if( vnode->tokenType == ttDoubleConstant )
  7648. {
  7649. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7650. // TODO: Check for overflow
  7651. size_t numScanned;
  7652. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  7653. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  7654. asASSERT(numScanned == vnode->tokenLength);
  7655. }
  7656. else if( vnode->tokenType == ttTrue ||
  7657. vnode->tokenType == ttFalse )
  7658. {
  7659. #if AS_SIZEOF_BOOL == 1
  7660. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7661. #else
  7662. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7663. #endif
  7664. }
  7665. else if( vnode->tokenType == ttStringConstant ||
  7666. vnode->tokenType == ttMultilineStringConstant ||
  7667. vnode->tokenType == ttHeredocStringConstant )
  7668. {
  7669. asCString str;
  7670. asCScriptNode *snode = vnode->firstChild;
  7671. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  7672. {
  7673. // Treat the single quoted string as a single character literal
  7674. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7675. asDWORD val = 0;
  7676. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  7677. {
  7678. // This is the start of a UTF8 encoded character. We need to decode it
  7679. val = asStringDecodeUTF8(str.AddressOf(), 0);
  7680. if( val == (asDWORD)-1 )
  7681. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7682. }
  7683. else
  7684. {
  7685. val = ProcessStringConstant(str, snode);
  7686. if( val == (asDWORD)-1 )
  7687. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7688. }
  7689. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  7690. }
  7691. else
  7692. {
  7693. // Process the string constants
  7694. while( snode )
  7695. {
  7696. asCString cat;
  7697. if( snode->tokenType == ttStringConstant )
  7698. {
  7699. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7700. ProcessStringConstant(cat, snode);
  7701. }
  7702. else if( snode->tokenType == ttMultilineStringConstant )
  7703. {
  7704. if( !engine->ep.allowMultilineStrings )
  7705. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  7706. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7707. ProcessStringConstant(cat, snode);
  7708. }
  7709. else if( snode->tokenType == ttHeredocStringConstant )
  7710. {
  7711. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  7712. ProcessHeredocStringConstant(cat, snode);
  7713. }
  7714. str += cat;
  7715. snode = snode->next;
  7716. }
  7717. // Call the string factory function to create a string object
  7718. asCScriptFunction *descr = engine->stringFactory;
  7719. if( descr == 0 )
  7720. {
  7721. // Error
  7722. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  7723. // Give dummy value
  7724. ctx->type.SetDummy();
  7725. return -1;
  7726. }
  7727. else
  7728. {
  7729. // Register the constant string with the engine
  7730. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  7731. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  7732. bool useVariable = false;
  7733. int stackOffset = 0;
  7734. if( descr->DoesReturnOnStack() )
  7735. {
  7736. useVariable = true;
  7737. stackOffset = AllocateVariable(descr->returnType, true);
  7738. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  7739. }
  7740. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  7741. }
  7742. }
  7743. }
  7744. else if( vnode->tokenType == ttNull )
  7745. {
  7746. ctx->bc.Instr(asBC_PshNull);
  7747. ctx->type.SetNullConstant();
  7748. }
  7749. else
  7750. asASSERT(false);
  7751. }
  7752. else if( vnode->nodeType == snFunctionCall )
  7753. {
  7754. // Determine the scope resolution
  7755. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  7756. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  7757. }
  7758. else if( vnode->nodeType == snConstructCall )
  7759. {
  7760. return CompileConstructCall(vnode, ctx);
  7761. }
  7762. else if( vnode->nodeType == snAssignment )
  7763. {
  7764. asSExprContext e(engine);
  7765. int r = CompileAssignment(vnode, &e);
  7766. if( r < 0 )
  7767. {
  7768. ctx->type.SetDummy();
  7769. return r;
  7770. }
  7771. MergeExprBytecodeAndType(ctx, &e);
  7772. }
  7773. else if( vnode->nodeType == snCast )
  7774. {
  7775. // Implement the cast operator
  7776. return CompileConversion(vnode, ctx);
  7777. }
  7778. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  7779. {
  7780. // This is a void expression
  7781. ctx->SetVoidExpression();
  7782. }
  7783. else if( vnode->nodeType == snFunction )
  7784. {
  7785. // This is an anonymous function
  7786. // Defer the evaluation of the function until it known where it
  7787. // will be used, which is where the signature will be defined
  7788. ctx->SetLambda(vnode);
  7789. }
  7790. else
  7791. asASSERT(false);
  7792. return 0;
  7793. }
  7794. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  7795. {
  7796. int charLiteral = -1;
  7797. // Process escape sequences
  7798. asCArray<char> str((int)cstr.GetLength());
  7799. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  7800. {
  7801. #ifdef AS_DOUBLEBYTE_CHARSET
  7802. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  7803. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  7804. {
  7805. // This is the lead character of a double byte character
  7806. // include the trail character without checking it's value.
  7807. str.PushLast(cstr[n]);
  7808. n++;
  7809. str.PushLast(cstr[n]);
  7810. continue;
  7811. }
  7812. #endif
  7813. asUINT val;
  7814. if( processEscapeSequences && cstr[n] == '\\' )
  7815. {
  7816. ++n;
  7817. if( n == cstr.GetLength() )
  7818. {
  7819. if( charLiteral == -1 ) charLiteral = 0;
  7820. return charLiteral;
  7821. }
  7822. // Hexadecimal escape sequences will allow the construction of
  7823. // invalid unicode sequences, but the string should also work as
  7824. // a bytearray so we must support this. The code for working with
  7825. // unicode text must be prepared to handle invalid unicode sequences
  7826. if( cstr[n] == 'x' || cstr[n] == 'X' )
  7827. {
  7828. ++n;
  7829. if( n == cstr.GetLength() ) break;
  7830. val = 0;
  7831. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  7832. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  7833. {
  7834. if( cstr[n] >= '0' && cstr[n] <= '9' )
  7835. val = val*16 + cstr[n] - '0';
  7836. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  7837. val = val*16 + cstr[n] - 'a' + 10;
  7838. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  7839. val = val*16 + cstr[n] - 'A' + 10;
  7840. else
  7841. break;
  7842. }
  7843. // Rewind one, since the loop will increment it again
  7844. n--;
  7845. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  7846. if( engine->ep.stringEncoding == 0 )
  7847. {
  7848. str.PushLast((asBYTE)val);
  7849. }
  7850. else
  7851. {
  7852. #ifndef AS_BIG_ENDIAN
  7853. str.PushLast((asBYTE)val);
  7854. str.PushLast((asBYTE)(val>>8));
  7855. #else
  7856. str.PushLast((asBYTE)(val>>8));
  7857. str.PushLast((asBYTE)val);
  7858. #endif
  7859. }
  7860. if( charLiteral == -1 ) charLiteral = val;
  7861. continue;
  7862. }
  7863. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  7864. {
  7865. // \u expects 4 hex digits
  7866. // \U expects 8 hex digits
  7867. bool expect2 = cstr[n] == 'u';
  7868. int c = expect2 ? 4 : 8;
  7869. val = 0;
  7870. for( ; c > 0; c-- )
  7871. {
  7872. ++n;
  7873. if( n == cstr.GetLength() ) break;
  7874. if( cstr[n] >= '0' && cstr[n] <= '9' )
  7875. val = val*16 + cstr[n] - '0';
  7876. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  7877. val = val*16 + cstr[n] - 'a' + 10;
  7878. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  7879. val = val*16 + cstr[n] - 'A' + 10;
  7880. else
  7881. break;
  7882. }
  7883. if( c != 0 )
  7884. {
  7885. // Give warning about invalid code point
  7886. // TODO: Need code position for warning
  7887. asCString msg;
  7888. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  7889. Warning(msg, node);
  7890. continue;
  7891. }
  7892. }
  7893. else
  7894. {
  7895. if( cstr[n] == '"' )
  7896. val = '"';
  7897. else if( cstr[n] == '\'' )
  7898. val = '\'';
  7899. else if( cstr[n] == 'n' )
  7900. val = '\n';
  7901. else if( cstr[n] == 'r' )
  7902. val = '\r';
  7903. else if( cstr[n] == 't' )
  7904. val = '\t';
  7905. else if( cstr[n] == '0' )
  7906. val = '\0';
  7907. else if( cstr[n] == '\\' )
  7908. val = '\\';
  7909. else
  7910. {
  7911. // Invalid escape sequence
  7912. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  7913. continue;
  7914. }
  7915. }
  7916. }
  7917. else
  7918. {
  7919. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  7920. {
  7921. unsigned int len;
  7922. val = asStringDecodeUTF8(&cstr[n], &len);
  7923. if( val == 0xFFFFFFFF )
  7924. {
  7925. // Incorrect UTF8 encoding. Use only the first byte
  7926. // TODO: Need code position for warning
  7927. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  7928. val = (unsigned char)cstr[n];
  7929. }
  7930. else
  7931. n += len-1;
  7932. }
  7933. else
  7934. val = (unsigned char)cstr[n];
  7935. }
  7936. // Add the character to the final string
  7937. char encodedValue[5];
  7938. int len;
  7939. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  7940. {
  7941. // Convert to UTF8 encoded
  7942. len = asStringEncodeUTF8(val, encodedValue);
  7943. }
  7944. else if( engine->ep.stringEncoding == 1 )
  7945. {
  7946. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  7947. len = asStringEncodeUTF16(val, encodedValue);
  7948. }
  7949. else
  7950. {
  7951. // Do not convert ASCII characters
  7952. encodedValue[0] = (asBYTE)val;
  7953. len = 1;
  7954. }
  7955. if( len < 0 )
  7956. {
  7957. // Give warning about invalid code point
  7958. // TODO: Need code position for warning
  7959. Warning(TXT_INVALID_UNICODE_VALUE, node);
  7960. }
  7961. else
  7962. {
  7963. // Add the encoded value to the final string
  7964. str.Concatenate(encodedValue, len);
  7965. if( charLiteral == -1 ) charLiteral = val;
  7966. }
  7967. }
  7968. cstr.Assign(str.AddressOf(), str.GetLength());
  7969. return charLiteral;
  7970. }
  7971. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  7972. {
  7973. // Remove first line if it only contains whitespace
  7974. int start;
  7975. for( start = 0; start < (int)str.GetLength(); start++ )
  7976. {
  7977. if( str[start] == '\n' )
  7978. {
  7979. // Remove the linebreak as well
  7980. start++;
  7981. break;
  7982. }
  7983. if( str[start] != ' ' &&
  7984. str[start] != '\t' &&
  7985. str[start] != '\r' )
  7986. {
  7987. // Don't remove anything
  7988. start = 0;
  7989. break;
  7990. }
  7991. }
  7992. // Remove the line after the last line break if it only contains whitespaces
  7993. int end;
  7994. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  7995. {
  7996. if( str[end] == '\n' )
  7997. {
  7998. // Don't remove the last line break
  7999. end++;
  8000. break;
  8001. }
  8002. if( str[end] != ' ' &&
  8003. str[end] != '\t' &&
  8004. str[end] != '\r' )
  8005. {
  8006. // Don't remove anything
  8007. end = (int)str.GetLength();
  8008. break;
  8009. }
  8010. }
  8011. if( end < 0 ) end = 0;
  8012. asCString tmp;
  8013. if( end > start )
  8014. tmp.Assign(&str[start], end-start);
  8015. ProcessStringConstant(tmp, node, false);
  8016. str = tmp;
  8017. }
  8018. int asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  8019. {
  8020. asSExprContext expr(engine);
  8021. asCDataType to;
  8022. bool anyErrors = false;
  8023. EImplicitConv convType;
  8024. if( node->nodeType == snConstructCall )
  8025. {
  8026. convType = asIC_EXPLICIT_VAL_CAST;
  8027. // Verify that there is only one argument
  8028. if( node->lastChild->firstChild == 0 ||
  8029. node->lastChild->firstChild != node->lastChild->lastChild )
  8030. {
  8031. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  8032. expr.type.SetDummy();
  8033. anyErrors = true;
  8034. }
  8035. else
  8036. {
  8037. // Compile the expression
  8038. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  8039. if( r < 0 )
  8040. anyErrors = true;
  8041. }
  8042. // Determine the requested type
  8043. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8044. to.MakeReadOnly(true); // Default to const
  8045. asASSERT(to.IsPrimitive());
  8046. }
  8047. else
  8048. {
  8049. convType = asIC_EXPLICIT_REF_CAST;
  8050. // Compile the expression
  8051. int r = CompileAssignment(node->lastChild, &expr);
  8052. if( r < 0 )
  8053. anyErrors = true;
  8054. // Determine the requested type
  8055. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8056. // If the type support object handles, then use it
  8057. if( to.SupportHandles() )
  8058. {
  8059. to.MakeHandle(true);
  8060. if( expr.type.dataType.IsObjectConst() )
  8061. to.MakeHandleToConst(true);
  8062. }
  8063. else if( !to.IsObjectHandle() )
  8064. {
  8065. // The cast<type> operator can only be used for reference casts
  8066. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  8067. anyErrors = true;
  8068. }
  8069. }
  8070. // Do not allow casting to non shared type if we're compiling a shared method
  8071. if( outFunc->IsShared() &&
  8072. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  8073. {
  8074. asCString msg;
  8075. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  8076. Error(msg, node);
  8077. anyErrors = true;
  8078. }
  8079. if( anyErrors )
  8080. {
  8081. // Assume that the error can be fixed and allow the compilation to continue
  8082. ctx->type.SetConstantDW(to, 0);
  8083. return -1;
  8084. }
  8085. ProcessPropertyGetAccessor(&expr, node);
  8086. // Don't allow any operators on expressions that take address of class method
  8087. if( expr.IsClassMethod() )
  8088. {
  8089. Error(TXT_INVALID_OP_ON_METHOD, node);
  8090. return -1;
  8091. }
  8092. // We don't want a reference for conversion casts
  8093. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  8094. {
  8095. if( expr.type.dataType.IsObject() )
  8096. Dereference(&expr, true);
  8097. else
  8098. ConvertToVariable(&expr);
  8099. }
  8100. ImplicitConversion(&expr, to, node, convType);
  8101. IsVariableInitialized(&expr.type, node);
  8102. // If no type conversion is really tried ignore it
  8103. if( to == expr.type.dataType )
  8104. {
  8105. // This will keep information about constant type
  8106. MergeExprBytecode(ctx, &expr);
  8107. ctx->type = expr.type;
  8108. return 0;
  8109. }
  8110. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  8111. {
  8112. MergeExprBytecode(ctx, &expr);
  8113. ctx->type = expr.type;
  8114. ctx->type.dataType.MakeReadOnly(true);
  8115. return 0;
  8116. }
  8117. // The implicit conversion already does most of the conversions permitted,
  8118. // here we'll only treat those conversions that require an explicit cast.
  8119. bool conversionOK = false;
  8120. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  8121. {
  8122. if( !expr.type.dataType.IsObject() )
  8123. ConvertToTempVariable(&expr);
  8124. if( to.IsObjectHandle() &&
  8125. expr.type.dataType.IsObjectHandle() &&
  8126. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  8127. {
  8128. conversionOK = CompileRefCast(&expr, to, true, node);
  8129. MergeExprBytecode(ctx, &expr);
  8130. ctx->type = expr.type;
  8131. }
  8132. }
  8133. if( conversionOK )
  8134. return 0;
  8135. // Conversion not available
  8136. ctx->type.SetDummy();
  8137. asCString strTo, strFrom;
  8138. strTo = to.Format(outFunc->nameSpace);
  8139. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  8140. asCString msg;
  8141. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  8142. Error(msg, node);
  8143. return -1;
  8144. }
  8145. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  8146. {
  8147. // deferAll is set to true if for example the function returns a reference, since in
  8148. // this case the function might be returning a reference to one of the arguments.
  8149. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  8150. // Parameters that are sent by reference should be assigned
  8151. // to the evaluated expression if it is an lvalue
  8152. // Evaluate the arguments from last to first
  8153. int n = (int)descr->parameterTypes.GetLength() - 1;
  8154. for( ; n >= 0; n-- )
  8155. {
  8156. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  8157. // If deferAll is set all objects passed by reference or handle must be deferred
  8158. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  8159. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  8160. {
  8161. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  8162. // For &inout, only store the argument if it is for a temporary variable
  8163. if( engine->ep.allowUnsafeReferences ||
  8164. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  8165. {
  8166. // Store the argument for later processing
  8167. asSDeferredParam outParam;
  8168. outParam.argNode = args[n]->exprNode;
  8169. outParam.argType = args[n]->type;
  8170. outParam.argInOutFlags = descr->inOutFlags[n];
  8171. outParam.origExpr = args[n]->origExpr;
  8172. ctx->deferredParams.PushLast(outParam);
  8173. }
  8174. }
  8175. else
  8176. {
  8177. // Release the temporary variable now
  8178. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  8179. }
  8180. // Move the argument's deferred expressions over to the final expression
  8181. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  8182. {
  8183. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  8184. args[n]->deferredParams[m].origExpr = 0;
  8185. }
  8186. args[n]->deferredParams.SetLength(0);
  8187. }
  8188. }
  8189. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  8190. {
  8191. if( isProcessingDeferredParams ) return;
  8192. isProcessingDeferredParams = true;
  8193. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  8194. {
  8195. asSDeferredParam outParam = ctx->deferredParams[n];
  8196. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  8197. {
  8198. // Just release the variable
  8199. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8200. }
  8201. else if( outParam.argInOutFlags == asTM_OUTREF )
  8202. {
  8203. asSExprContext *expr = outParam.origExpr;
  8204. outParam.origExpr = 0;
  8205. if( outParam.argType.dataType.IsObjectHandle() )
  8206. {
  8207. // Implicitly convert the value to a handle
  8208. if( expr->type.dataType.IsObjectHandle() )
  8209. expr->type.isExplicitHandle = true;
  8210. }
  8211. // Verify that the expression result in a lvalue, or a property accessor
  8212. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  8213. {
  8214. asSExprContext rctx(engine);
  8215. rctx.type = outParam.argType;
  8216. if( rctx.type.dataType.IsPrimitive() )
  8217. rctx.type.dataType.MakeReference(false);
  8218. else
  8219. {
  8220. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  8221. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  8222. if( expr->type.isExplicitHandle )
  8223. rctx.type.isExplicitHandle = true;
  8224. }
  8225. asSExprContext o(engine);
  8226. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  8227. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  8228. // The assignment may itself have resulted in a new temporary variable, e.g. if
  8229. // the opAssign returns a non-reference. We must release this temporary variable
  8230. // since it won't be used
  8231. ReleaseTemporaryVariable(o.type, &o.bc);
  8232. MergeExprBytecode(ctx, &o);
  8233. }
  8234. else
  8235. {
  8236. // We must still evaluate the expression
  8237. MergeExprBytecode(ctx, expr);
  8238. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  8239. ctx->bc.Instr(asBC_PopPtr);
  8240. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  8241. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  8242. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  8243. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8244. }
  8245. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  8246. // Delete the original expression context
  8247. asDELETE(expr,asSExprContext);
  8248. }
  8249. else // &inout
  8250. {
  8251. if( outParam.argType.isTemporary )
  8252. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8253. else if( !outParam.argType.isVariable )
  8254. {
  8255. if( outParam.argType.dataType.IsObject() &&
  8256. ((outParam.argType.dataType.GetBehaviour()->addref &&
  8257. outParam.argType.dataType.GetBehaviour()->release) ||
  8258. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  8259. {
  8260. // Release the object handle that was taken to guarantee the reference
  8261. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8262. }
  8263. }
  8264. }
  8265. }
  8266. ctx->deferredParams.SetLength(0);
  8267. isProcessingDeferredParams = false;
  8268. }
  8269. int asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  8270. {
  8271. // The first node is a datatype node
  8272. asCString name;
  8273. asCTypeInfo tempObj;
  8274. bool onHeap = true;
  8275. asCArray<int> funcs;
  8276. bool error = false;
  8277. // It is possible that the name is really a constructor
  8278. asCDataType dt;
  8279. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8280. if( dt.IsPrimitive() )
  8281. {
  8282. // This is a cast to a primitive type
  8283. return CompileConversion(node, ctx);
  8284. }
  8285. if( dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  8286. {
  8287. // Types declared as implicit handle must not attempt to construct a handle
  8288. dt.MakeHandle(false);
  8289. }
  8290. // Don't accept syntax like object@(expr)
  8291. if( dt.IsObjectHandle() )
  8292. {
  8293. asCString str;
  8294. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  8295. Error(str, node);
  8296. ctx->type.SetDummy();
  8297. return -1;
  8298. }
  8299. if( !dt.CanBeInstantiated() )
  8300. {
  8301. asCString str;
  8302. if( dt.IsAbstractClass() )
  8303. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  8304. else if( dt.IsInterface() )
  8305. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  8306. else
  8307. // TODO: Improve error message to explain why
  8308. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  8309. Error(str, node);
  8310. ctx->type.SetDummy();
  8311. return -1;
  8312. }
  8313. // Do not allow constructing non-shared types in shared functions
  8314. if( outFunc->IsShared() &&
  8315. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  8316. {
  8317. asCString msg;
  8318. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  8319. Error(msg, node);
  8320. return -1;
  8321. }
  8322. // Compile the arguments
  8323. asCArray<asSExprContext *> args;
  8324. asCArray<asSNamedArgument> namedArgs;
  8325. asCArray<asCTypeInfo> temporaryVariables;
  8326. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  8327. {
  8328. // Check for a value cast behaviour
  8329. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  8330. {
  8331. asSExprContext conv(engine);
  8332. conv.type = args[0]->type;
  8333. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  8334. // Don't use this if the cost is 0 because it would mean that nothing
  8335. // is done and the scipt wants a new value to be constructed
  8336. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  8337. {
  8338. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  8339. ctx->bc.AddCode(&args[0]->bc);
  8340. ctx->type = args[0]->type;
  8341. asDELETE(args[0],asSExprContext);
  8342. return 0;
  8343. }
  8344. }
  8345. // Check for possible constructor/factory
  8346. name = dt.Format(outFunc->nameSpace);
  8347. asSTypeBehaviour *beh = dt.GetBehaviour();
  8348. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  8349. {
  8350. funcs = beh->constructors;
  8351. // Value types and script types are allocated through the constructor
  8352. tempObj.dataType = dt;
  8353. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  8354. tempObj.dataType.MakeReference(true);
  8355. tempObj.isTemporary = true;
  8356. tempObj.isVariable = true;
  8357. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  8358. // Push the address of the object on the stack
  8359. if( onHeap )
  8360. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  8361. }
  8362. else
  8363. funcs = beh->factories;
  8364. // Special case: Allow calling func(void) with a void expression.
  8365. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  8366. {
  8367. // Evaluate the expression before the function call
  8368. MergeExprBytecode(ctx, args[0]);
  8369. asDELETE(args[0],asSExprContext);
  8370. args.SetLength(0);
  8371. }
  8372. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  8373. // If none has been registered, just allocate the variable and push it on the stack.
  8374. if( args.GetLength() == 0 )
  8375. {
  8376. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  8377. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  8378. {
  8379. // Call the default constructor
  8380. ctx->type = tempObj;
  8381. if( onHeap )
  8382. {
  8383. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  8384. ctx->bc.RemoveLastInstr();
  8385. }
  8386. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  8387. // Push the reference on the stack
  8388. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8389. return 0;
  8390. }
  8391. }
  8392. // Special case: If this is a construction of a delegate and the expression names an object method
  8393. if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
  8394. {
  8395. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  8396. // case no object delegate will be created, but instead a delegate for a function pointer
  8397. // In theory a simple cast would be good in this case, but this is a construct call so it
  8398. // is expected that a new object is created.
  8399. dt.MakeHandle(true);
  8400. ctx->type.Set(dt);
  8401. // The delegate must be able to hold on to a reference to the object
  8402. if( !args[0]->type.dataType.SupportHandles() )
  8403. {
  8404. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  8405. error = true;
  8406. }
  8407. else
  8408. {
  8409. // Filter the available object methods to find the one that matches the func def
  8410. asCObjectType *type = args[0]->type.dataType.GetObjectType();
  8411. asCScriptFunction *bestMethod = 0;
  8412. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  8413. {
  8414. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  8415. if( func->name != args[0]->methodName )
  8416. continue;
  8417. // If the expression is for a const object, then only const methods should be accepted
  8418. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  8419. continue;
  8420. if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
  8421. {
  8422. bestMethod = func;
  8423. // If the expression is non-const the non-const overloaded method has priority
  8424. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  8425. break;
  8426. }
  8427. }
  8428. if( bestMethod )
  8429. {
  8430. // The object pointer is already on the stack
  8431. MergeExprBytecode(ctx, args[0]);
  8432. // Push the function pointer as an additional argument
  8433. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  8434. // Call the factory function for the delegate
  8435. asCArray<int> funcs;
  8436. builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
  8437. asASSERT( funcs.GetLength() == 1 );
  8438. ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
  8439. // Store the returned delegate in a temporary variable
  8440. int returnOffset = AllocateVariable(dt, true, false);
  8441. dt.MakeReference(true);
  8442. ctx->type.SetVariable(dt, returnOffset, true);
  8443. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  8444. // Push a reference to the temporary variable on the stack
  8445. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  8446. // Clean up arguments
  8447. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  8448. }
  8449. else
  8450. {
  8451. asCString msg;
  8452. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
  8453. Error(msg.AddressOf(), node);
  8454. error = true;
  8455. }
  8456. }
  8457. // Clean-up arg
  8458. asDELETE(args[0],asSExprContext);
  8459. return error ? -1 : 0;
  8460. }
  8461. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  8462. if( funcs.GetLength() != 1 )
  8463. {
  8464. // The error was reported by MatchFunctions()
  8465. error = true;
  8466. // Dummy value
  8467. ctx->type.SetDummy();
  8468. }
  8469. else
  8470. {
  8471. // TODO: Clean up: Merge this with MakeFunctionCall
  8472. // Add the default values for arguments not explicitly supplied
  8473. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], dt.GetObjectType(), &namedArgs);
  8474. if( r == asSUCCESS )
  8475. {
  8476. asCByteCode objBC(engine);
  8477. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  8478. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  8479. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  8480. {
  8481. // If the object is allocated on the stack, then call the constructor as a normal function
  8482. if( onHeap )
  8483. {
  8484. int offset = 0;
  8485. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  8486. for( asUINT n = 0; n < args.GetLength(); n++ )
  8487. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  8488. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  8489. }
  8490. else
  8491. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8492. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  8493. // Add tag that the object has been initialized
  8494. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  8495. // The constructor doesn't return anything,
  8496. // so we have to manually inform the type of
  8497. // the return value
  8498. ctx->type = tempObj;
  8499. if( !onHeap )
  8500. ctx->type.dataType.MakeReference(false);
  8501. // Push the address of the object on the stack again
  8502. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8503. }
  8504. else
  8505. {
  8506. // Call the factory to create the reference type
  8507. PerformFunctionCall(funcs[0], ctx, false, &args);
  8508. }
  8509. }
  8510. else
  8511. error = true;
  8512. }
  8513. }
  8514. else
  8515. {
  8516. // Failed to compile the argument list, set the result to the dummy type
  8517. ctx->type.SetDummy();
  8518. error = true;
  8519. }
  8520. // Cleanup
  8521. for( asUINT n = 0; n < args.GetLength(); n++ )
  8522. if( args[n] )
  8523. {
  8524. asDELETE(args[n],asSExprContext);
  8525. }
  8526. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  8527. if( namedArgs[n].ctx )
  8528. {
  8529. asDELETE(namedArgs[n].ctx,asSExprContext);
  8530. }
  8531. return error ? -1 : 0;
  8532. }
  8533. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  8534. {
  8535. asCTypeInfo tempObj;
  8536. asCArray<int> funcs;
  8537. int localVar = -1;
  8538. bool initializeMembers = false;
  8539. asSExprContext funcExpr(engine);
  8540. asCScriptNode *nm = node->lastChild->prev;
  8541. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  8542. // First check for a local variable as it would take precedence
  8543. // Must not allow function names, nor global variables to be returned in this instance
  8544. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  8545. if( objectType == 0 )
  8546. {
  8547. localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true);
  8548. if( localVar >= 0 &&
  8549. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8550. funcExpr.methodName == "" )
  8551. {
  8552. // The variable is not a function or object with opCall
  8553. asCString msg;
  8554. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8555. Error(msg, node);
  8556. return -1;
  8557. }
  8558. // If the name matches a method name, then reset the indicator that nothing was found
  8559. if( funcExpr.methodName != "" )
  8560. localVar = -1;
  8561. }
  8562. if( localVar < 0 )
  8563. {
  8564. // If this is an expression post op, or if a class method is
  8565. // being compiled, then we should look for matching class methods
  8566. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  8567. {
  8568. // If we're compiling a constructor and the name of the function is super then
  8569. // the constructor of the base class is being called.
  8570. // super cannot be prefixed with a scope operator
  8571. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  8572. {
  8573. // If the class is not derived from anyone else, calling super should give an error
  8574. if( outFunc && outFunc->objectType->derivedFrom )
  8575. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  8576. // Must not allow calling base class' constructor multiple times
  8577. if( continueLabels.GetLength() > 0 )
  8578. {
  8579. // If a continue label is set we are in a loop
  8580. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  8581. }
  8582. else if( breakLabels.GetLength() > 0 )
  8583. {
  8584. // TODO: inheritance: Should eventually allow constructors in switch statements
  8585. // If a break label is set we are either in a loop or a switch statements
  8586. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  8587. }
  8588. else if( m_isConstructorCalled )
  8589. {
  8590. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  8591. }
  8592. m_isConstructorCalled = true;
  8593. // We need to initialize the class members, but only after all the deferred arguments have been completed
  8594. initializeMembers = true;
  8595. }
  8596. else
  8597. {
  8598. // The scope can be used to specify the base class
  8599. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope, node, script);
  8600. }
  8601. // It is still possible that there is a class member of a function type or a type with opCall methods
  8602. if( funcs.GetLength() == 0 )
  8603. {
  8604. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType);
  8605. if( r >= 0 &&
  8606. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8607. funcExpr.methodName == "" )
  8608. {
  8609. // The variable is not a function
  8610. asCString msg;
  8611. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8612. Error(msg, node);
  8613. return -1;
  8614. }
  8615. // If the name is an access property, make sure the original value isn't
  8616. // dereferenced when calling the access property as part a dot post operator
  8617. if( objectType && (funcExpr.property_get || funcExpr.property_set) && !ctx->type.dataType.IsReference() )
  8618. funcExpr.property_ref = false;
  8619. }
  8620. // If a class method is being called implicitly, then add the this pointer for the call
  8621. if( funcs.GetLength() && !objectType )
  8622. {
  8623. objectType = outFunc->objectType;
  8624. asCDataType dt = asCDataType::CreateObject(objectType, false);
  8625. // The object pointer is located at stack position 0
  8626. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8627. ctx->type.SetVariable(dt, 0, false);
  8628. ctx->type.dataType.MakeReference(true);
  8629. Dereference(ctx, true);
  8630. }
  8631. }
  8632. // If it is not a class method or member function pointer,
  8633. // then look for global functions or global function pointers,
  8634. // unless this is an expression post op, incase only member
  8635. // functions are expected
  8636. if( objectType == 0 && funcs.GetLength() == 0 && (funcExpr.type.dataType.GetFuncDef() == 0 || funcExpr.type.dataType.IsObject()) )
  8637. {
  8638. // The scope is used to define the namespace
  8639. asSNameSpace *ns = DetermineNameSpace(scope);
  8640. if( ns )
  8641. {
  8642. // Search recursively in parent namespaces
  8643. while( ns && funcs.GetLength() == 0 && funcExpr.type.dataType.GetFuncDef() == 0 )
  8644. {
  8645. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8646. if( funcs.GetLength() == 0 )
  8647. {
  8648. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true);
  8649. if( r >= 0 &&
  8650. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8651. funcExpr.methodName == "" )
  8652. {
  8653. // The variable is not a function
  8654. asCString msg;
  8655. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8656. Error(msg, node);
  8657. return -1;
  8658. }
  8659. }
  8660. ns = engine->GetParentNameSpace(ns);
  8661. }
  8662. }
  8663. else
  8664. {
  8665. asCString msg;
  8666. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  8667. Error(msg, node);
  8668. return -1;
  8669. }
  8670. }
  8671. }
  8672. if( funcs.GetLength() == 0 )
  8673. {
  8674. if( funcExpr.type.dataType.GetFuncDef() )
  8675. {
  8676. funcs.PushLast(funcExpr.type.dataType.GetFuncDef()->id);
  8677. }
  8678. else if( funcExpr.type.dataType.IsObject() )
  8679. {
  8680. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  8681. if( ctx->type.isTemporary )
  8682. {
  8683. asASSERT( objectType );
  8684. asSDeferredParam deferred;
  8685. deferred.origExpr = 0;
  8686. deferred.argInOutFlags = asTM_INREF;
  8687. deferred.argNode = 0;
  8688. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8689. ctx->deferredParams.PushLast(deferred);
  8690. }
  8691. if( funcExpr.property_get == 0 )
  8692. Dereference(ctx, true);
  8693. // Add the bytecode for accessing the object on which opCall will be called
  8694. MergeExprBytecodeAndType(ctx, &funcExpr);
  8695. ProcessPropertyGetAccessor(ctx, node);
  8696. Dereference(ctx, true);
  8697. objectType = funcExpr.type.dataType.GetObjectType();
  8698. // Get the opCall methods from the object type
  8699. if( funcExpr.type.dataType.IsObjectHandle() )
  8700. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  8701. else
  8702. objIsConst = funcExpr.type.dataType.IsReadOnly();
  8703. builder->GetObjectMethodDescriptions("opCall", funcExpr.type.dataType.GetObjectType(), funcs, objIsConst);
  8704. }
  8705. }
  8706. // Compile the arguments
  8707. asCArray<asSExprContext *> args;
  8708. asCArray<asSNamedArgument> namedArgs;
  8709. bool isOK = true;
  8710. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  8711. {
  8712. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  8713. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  8714. {
  8715. // Evaluate the expression before the function call
  8716. MergeExprBytecode(ctx, args[0]);
  8717. asDELETE(args[0],asSExprContext);
  8718. args.SetLength(0);
  8719. }
  8720. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  8721. if( funcs.GetLength() != 1 )
  8722. {
  8723. // The error was reported by MatchFunctions()
  8724. // Dummy value
  8725. ctx->type.SetDummy();
  8726. isOK = false;
  8727. }
  8728. else
  8729. {
  8730. // Add the default values for arguments not explicitly supplied
  8731. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  8732. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8733. // is it enough to make sure it is in a local variable?
  8734. // For function pointer we must guarantee that the function is safe, i.e.
  8735. // by first storing the function pointer in a local variable (if it isn't already in one)
  8736. if( r == asSUCCESS )
  8737. {
  8738. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  8739. if( func->funcType == asFUNC_FUNCDEF )
  8740. {
  8741. if( objectType && funcExpr.property_get <= 0 )
  8742. {
  8743. // Dereference the object pointer to access the member
  8744. Dereference(ctx, true);
  8745. }
  8746. if( funcExpr.property_get > 0 )
  8747. {
  8748. ProcessPropertyGetAccessor(&funcExpr, node);
  8749. Dereference(&funcExpr, true);
  8750. }
  8751. else
  8752. {
  8753. Dereference(&funcExpr, true);
  8754. ConvertToVariable(&funcExpr);
  8755. }
  8756. // The actual function should be called as if a global function
  8757. objectType = 0;
  8758. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  8759. funcExpr.bc.Instr(asBC_PopPtr);
  8760. asCTypeInfo tmp = ctx->type;
  8761. MergeExprBytecodeAndType(ctx, &funcExpr);
  8762. ReleaseTemporaryVariable(tmp, &ctx->bc);
  8763. }
  8764. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  8765. }
  8766. else
  8767. isOK = false;
  8768. }
  8769. }
  8770. else
  8771. {
  8772. // Failed to compile the argument list, set the dummy type and continue compilation
  8773. ctx->type.SetDummy();
  8774. isOK = false;
  8775. }
  8776. // Cleanup
  8777. for( asUINT n = 0; n < args.GetLength(); n++ )
  8778. if( args[n] )
  8779. {
  8780. asDELETE(args[n],asSExprContext);
  8781. }
  8782. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  8783. if( namedArgs[n].ctx )
  8784. {
  8785. asDELETE(namedArgs[n].ctx,asSExprContext);
  8786. }
  8787. if( initializeMembers )
  8788. {
  8789. asASSERT( m_isConstructor );
  8790. // Need to initialize members here, as they may use the properties of the base class
  8791. // If there are multiple paths that call super(), then there will also be multiple
  8792. // locations with initializations of the members. It is not possible to consolidate
  8793. // these in one place, as the expressions for the initialization are evaluated where
  8794. // they are compiled, which means that they may access different variables depending
  8795. // on the scope where super() is called.
  8796. // Members that don't have an explicit initialization expression will be initialized
  8797. // beginning of the constructor as they are guaranteed not to use at the any
  8798. // members of the base class.
  8799. CompileMemberInitialization(&ctx->bc, false);
  8800. }
  8801. return isOK ? 0 : -1;
  8802. }
  8803. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  8804. {
  8805. asSNameSpace *ns;
  8806. if( scope == "" )
  8807. {
  8808. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  8809. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  8810. ns = outFunc->nameSpace;
  8811. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  8812. ns = outFunc->objectType->nameSpace;
  8813. else
  8814. ns = engine->nameSpaces[0];
  8815. }
  8816. else if( scope == "::" )
  8817. ns = engine->nameSpaces[0];
  8818. else
  8819. ns = engine->FindNameSpace(scope.AddressOf());
  8820. return ns;
  8821. }
  8822. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  8823. {
  8824. int op = node->tokenType;
  8825. // Don't allow any prefix operators except handle on expressions that take address of class method
  8826. if( ctx->IsClassMethod() && op != ttHandle )
  8827. {
  8828. Error(TXT_INVALID_OP_ON_METHOD, node);
  8829. return -1;
  8830. }
  8831. // Don't allow any operators on void expressions
  8832. if( ctx->IsVoidExpression() )
  8833. {
  8834. Error(TXT_VOID_CANT_BE_OPERAND, node);
  8835. return -1;
  8836. }
  8837. IsVariableInitialized(&ctx->type, node);
  8838. if( op == ttHandle )
  8839. {
  8840. if( ctx->methodName != "" )
  8841. {
  8842. // Don't allow taking the handle of a handle
  8843. if( ctx->type.isExplicitHandle )
  8844. {
  8845. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8846. return -1;
  8847. }
  8848. }
  8849. else
  8850. {
  8851. // Don't allow taking handle of a handle, i.e. @@
  8852. if( ctx->type.isExplicitHandle )
  8853. {
  8854. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8855. return -1;
  8856. }
  8857. // @null is allowed even though it is implicit
  8858. if( !ctx->type.IsNullConstant() )
  8859. {
  8860. // Verify that the type allow its handle to be taken
  8861. if( !ctx->type.dataType.IsObject() ||
  8862. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  8863. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  8864. {
  8865. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8866. return -1;
  8867. }
  8868. // Objects that are not local variables are not references
  8869. // Objects allocated on the stack are also not marked as references
  8870. if( !ctx->type.dataType.IsReference() &&
  8871. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  8872. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  8873. {
  8874. Error(TXT_NOT_VALID_REFERENCE, node);
  8875. return -1;
  8876. }
  8877. // Convert the expression to a handle
  8878. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  8879. {
  8880. asCDataType to = ctx->type.dataType;
  8881. to.MakeHandle(true);
  8882. to.MakeReference(true);
  8883. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  8884. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  8885. asASSERT( ctx->type.dataType.IsObjectHandle() );
  8886. }
  8887. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  8888. {
  8889. // For the ASHANDLE type we'll simply set the expression as a handle
  8890. ctx->type.dataType.MakeHandle(true);
  8891. }
  8892. }
  8893. }
  8894. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  8895. ctx->type.isExplicitHandle = true;
  8896. }
  8897. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  8898. {
  8899. // Look for the appropriate method
  8900. // There is no overloadable operator for unary plus
  8901. const char *opName = 0;
  8902. switch( op )
  8903. {
  8904. case ttMinus: opName = "opNeg"; break;
  8905. case ttBitNot: opName = "opCom"; break;
  8906. case ttInc: opName = "opPreInc"; break;
  8907. case ttDec: opName = "opPreDec"; break;
  8908. }
  8909. if( opName )
  8910. {
  8911. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  8912. ProcessPropertyGetAccessor(ctx, node);
  8913. // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method
  8914. // Find the correct method
  8915. bool isConst = ctx->type.dataType.IsObjectConst();
  8916. asCArray<int> funcs;
  8917. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8918. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8919. {
  8920. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8921. if( func->name == opName &&
  8922. func->parameterTypes.GetLength() == 0 &&
  8923. (!isConst || func->isReadOnly) )
  8924. {
  8925. funcs.PushLast(func->id);
  8926. }
  8927. }
  8928. // Did we find the method?
  8929. if( funcs.GetLength() == 1 )
  8930. {
  8931. asCArray<asSExprContext *> args;
  8932. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  8933. return 0;
  8934. }
  8935. else if( funcs.GetLength() == 0 )
  8936. {
  8937. asCString str;
  8938. str = asCString(opName) + "()";
  8939. if( isConst )
  8940. str += " const";
  8941. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  8942. Error(str, node);
  8943. ctx->type.SetDummy();
  8944. return -1;
  8945. }
  8946. else if( funcs.GetLength() > 1 )
  8947. {
  8948. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8949. PrintMatchingFuncs(funcs, node);
  8950. ctx->type.SetDummy();
  8951. return -1;
  8952. }
  8953. }
  8954. else if( op == ttPlus )
  8955. {
  8956. Error(TXT_ILLEGAL_OPERATION, node);
  8957. ctx->type.SetDummy();
  8958. return -1;
  8959. }
  8960. }
  8961. else if( op == ttPlus || op == ttMinus )
  8962. {
  8963. // This is only for primitives. Objects are treated in the above block
  8964. // Make sure the type is a math type
  8965. if( !(ctx->type.dataType.IsIntegerType() ||
  8966. ctx->type.dataType.IsUnsignedType() ||
  8967. ctx->type.dataType.IsFloatType() ||
  8968. ctx->type.dataType.IsDoubleType() ) )
  8969. {
  8970. Error(TXT_ILLEGAL_OPERATION, node);
  8971. return -1;
  8972. }
  8973. ProcessPropertyGetAccessor(ctx, node);
  8974. asCDataType to = ctx->type.dataType;
  8975. if( ctx->type.dataType.IsUnsignedType() )
  8976. {
  8977. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8978. to = asCDataType::CreatePrimitive(ttInt8, false);
  8979. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8980. to = asCDataType::CreatePrimitive(ttInt16, false);
  8981. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8982. to = asCDataType::CreatePrimitive(ttInt, false);
  8983. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  8984. to = asCDataType::CreatePrimitive(ttInt64, false);
  8985. else
  8986. {
  8987. Error(TXT_INVALID_TYPE, node);
  8988. return -1;
  8989. }
  8990. }
  8991. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  8992. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  8993. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  8994. if( !ctx->type.isConstant )
  8995. {
  8996. ConvertToTempVariable(ctx);
  8997. asASSERT(!ctx->type.isLValue);
  8998. if( op == ttMinus )
  8999. {
  9000. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9001. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  9002. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9003. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  9004. else if( ctx->type.dataType.IsFloatType() )
  9005. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  9006. else if( ctx->type.dataType.IsDoubleType() )
  9007. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  9008. else
  9009. {
  9010. Error(TXT_ILLEGAL_OPERATION, node);
  9011. return -1;
  9012. }
  9013. return 0;
  9014. }
  9015. }
  9016. else
  9017. {
  9018. if( op == ttMinus )
  9019. {
  9020. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9021. ctx->type.intValue = -ctx->type.intValue;
  9022. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9023. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  9024. else if( ctx->type.dataType.IsFloatType() )
  9025. ctx->type.floatValue = -ctx->type.floatValue;
  9026. else if( ctx->type.dataType.IsDoubleType() )
  9027. ctx->type.doubleValue = -ctx->type.doubleValue;
  9028. else
  9029. {
  9030. Error(TXT_ILLEGAL_OPERATION, node);
  9031. return -1;
  9032. }
  9033. return 0;
  9034. }
  9035. }
  9036. }
  9037. else if( op == ttNot )
  9038. {
  9039. // Allow value types to be converted to bool using 'bool opImplConv()'
  9040. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  9041. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  9042. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  9043. {
  9044. if( ctx->type.isConstant )
  9045. {
  9046. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9047. return 0;
  9048. }
  9049. ProcessPropertyGetAccessor(ctx, node);
  9050. ConvertToTempVariable(ctx);
  9051. asASSERT(!ctx->type.isLValue);
  9052. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9053. }
  9054. else
  9055. {
  9056. Error(TXT_ILLEGAL_OPERATION, node);
  9057. return -1;
  9058. }
  9059. }
  9060. else if( op == ttBitNot )
  9061. {
  9062. ProcessPropertyGetAccessor(ctx, node);
  9063. asCDataType to = ctx->type.dataType;
  9064. if( ctx->type.dataType.IsIntegerType() )
  9065. {
  9066. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9067. to = asCDataType::CreatePrimitive(ttUInt8, false);
  9068. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9069. to = asCDataType::CreatePrimitive(ttUInt16, false);
  9070. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9071. to = asCDataType::CreatePrimitive(ttUInt, false);
  9072. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  9073. to = asCDataType::CreatePrimitive(ttUInt64, false);
  9074. else
  9075. {
  9076. Error(TXT_INVALID_TYPE, node);
  9077. return -1;
  9078. }
  9079. }
  9080. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  9081. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  9082. if( ctx->type.dataType.IsUnsignedType() )
  9083. {
  9084. if( ctx->type.isConstant )
  9085. {
  9086. ctx->type.qwordValue = ~ctx->type.qwordValue;
  9087. return 0;
  9088. }
  9089. ConvertToTempVariable(ctx);
  9090. asASSERT(!ctx->type.isLValue);
  9091. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9092. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  9093. else
  9094. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  9095. }
  9096. else
  9097. {
  9098. Error(TXT_ILLEGAL_OPERATION, node);
  9099. return -1;
  9100. }
  9101. }
  9102. else if( op == ttInc || op == ttDec )
  9103. {
  9104. // Need a reference to the primitive that will be updated
  9105. // The result of this expression is the same reference as before
  9106. // Make sure the reference isn't a temporary variable
  9107. if( ctx->type.isTemporary )
  9108. {
  9109. Error(TXT_REF_IS_TEMP, node);
  9110. return -1;
  9111. }
  9112. if( ctx->type.dataType.IsReadOnly() )
  9113. {
  9114. Error(TXT_REF_IS_READ_ONLY, node);
  9115. return -1;
  9116. }
  9117. if( ctx->property_get || ctx->property_set )
  9118. {
  9119. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  9120. return -1;
  9121. }
  9122. if( !ctx->type.isLValue )
  9123. {
  9124. Error(TXT_NOT_LVALUE, node);
  9125. return -1;
  9126. }
  9127. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9128. ConvertToReference(ctx);
  9129. else if( !ctx->type.dataType.IsReference() )
  9130. {
  9131. Error(TXT_NOT_VALID_REFERENCE, node);
  9132. return -1;
  9133. }
  9134. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  9135. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  9136. {
  9137. if( op == ttInc )
  9138. ctx->bc.Instr(asBC_INCi64);
  9139. else
  9140. ctx->bc.Instr(asBC_DECi64);
  9141. }
  9142. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  9143. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  9144. {
  9145. if( op == ttInc )
  9146. ctx->bc.Instr(asBC_INCi);
  9147. else
  9148. ctx->bc.Instr(asBC_DECi);
  9149. }
  9150. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  9151. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  9152. {
  9153. if( op == ttInc )
  9154. ctx->bc.Instr(asBC_INCi16);
  9155. else
  9156. ctx->bc.Instr(asBC_DECi16);
  9157. }
  9158. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  9159. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  9160. {
  9161. if( op == ttInc )
  9162. ctx->bc.Instr(asBC_INCi8);
  9163. else
  9164. ctx->bc.Instr(asBC_DECi8);
  9165. }
  9166. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  9167. {
  9168. if( op == ttInc )
  9169. ctx->bc.Instr(asBC_INCf);
  9170. else
  9171. ctx->bc.Instr(asBC_DECf);
  9172. }
  9173. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  9174. {
  9175. if( op == ttInc )
  9176. ctx->bc.Instr(asBC_INCd);
  9177. else
  9178. ctx->bc.Instr(asBC_DECd);
  9179. }
  9180. else
  9181. {
  9182. Error(TXT_ILLEGAL_OPERATION, node);
  9183. return -1;
  9184. }
  9185. }
  9186. else
  9187. {
  9188. // Unknown operator
  9189. asASSERT(false);
  9190. return -1;
  9191. }
  9192. return 0;
  9193. }
  9194. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  9195. {
  9196. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9197. {
  9198. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  9199. ctx->type.dataType.MakeReference(true);
  9200. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  9201. }
  9202. }
  9203. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  9204. {
  9205. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  9206. }
  9207. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  9208. {
  9209. if( engine->ep.propertyAccessorMode == 0 )
  9210. {
  9211. // Property accessors have been disabled by the application
  9212. return 0;
  9213. }
  9214. int getId = 0, setId = 0;
  9215. asCString getName = "get_" + name;
  9216. asCString setName = "set_" + name;
  9217. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  9218. if( ctx->type.dataType.IsObject() )
  9219. {
  9220. asASSERT( ns == 0 );
  9221. // Don't look for property accessors in script classes if the script
  9222. // property accessors have been disabled by the application
  9223. if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
  9224. engine->ep.propertyAccessorMode == 2 )
  9225. {
  9226. // Check if the object has any methods with the corresponding accessor name(s)
  9227. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  9228. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9229. {
  9230. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  9231. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  9232. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  9233. {
  9234. if( getId == 0 )
  9235. getId = ot->methods[n];
  9236. else
  9237. {
  9238. if( multipleGetFuncs.GetLength() == 0 )
  9239. multipleGetFuncs.PushLast(getId);
  9240. multipleGetFuncs.PushLast(ot->methods[n]);
  9241. }
  9242. }
  9243. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  9244. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  9245. {
  9246. if( setId == 0 )
  9247. setId = ot->methods[n];
  9248. else
  9249. {
  9250. if( multipleSetFuncs.GetLength() == 0 )
  9251. multipleSetFuncs.PushLast(setId);
  9252. multipleSetFuncs.PushLast(ot->methods[n]);
  9253. }
  9254. }
  9255. }
  9256. }
  9257. }
  9258. else
  9259. {
  9260. asASSERT( ns != 0 );
  9261. // Look for appropriate global functions.
  9262. asCArray<int> funcs;
  9263. asUINT n;
  9264. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  9265. for( n = 0; n < funcs.GetLength(); n++ )
  9266. {
  9267. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  9268. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  9269. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  9270. {
  9271. if( getId == 0 )
  9272. getId = funcs[n];
  9273. else
  9274. {
  9275. if( multipleGetFuncs.GetLength() == 0 )
  9276. multipleGetFuncs.PushLast(getId);
  9277. multipleGetFuncs.PushLast(funcs[n]);
  9278. }
  9279. }
  9280. }
  9281. funcs.SetLength(0);
  9282. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  9283. for( n = 0; n < funcs.GetLength(); n++ )
  9284. {
  9285. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  9286. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  9287. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  9288. {
  9289. if( setId == 0 )
  9290. setId = funcs[n];
  9291. else
  9292. {
  9293. if( multipleSetFuncs.GetLength() == 0 )
  9294. multipleSetFuncs.PushLast(getId);
  9295. multipleSetFuncs.PushLast(funcs[n]);
  9296. }
  9297. }
  9298. }
  9299. }
  9300. bool isConst = ctx->type.dataType.IsObjectConst();
  9301. // Check for multiple matches
  9302. if( multipleGetFuncs.GetLength() > 0 )
  9303. {
  9304. // Filter the list by constness
  9305. FilterConst(multipleGetFuncs, !isConst);
  9306. if( multipleGetFuncs.GetLength() > 1 )
  9307. {
  9308. asCString str;
  9309. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  9310. Error(str, node);
  9311. PrintMatchingFuncs(multipleGetFuncs, node);
  9312. return -1;
  9313. }
  9314. else
  9315. {
  9316. // The id may have changed
  9317. getId = multipleGetFuncs[0];
  9318. }
  9319. }
  9320. if( multipleSetFuncs.GetLength() > 0 )
  9321. {
  9322. // Filter the list by constness
  9323. FilterConst(multipleSetFuncs, !isConst);
  9324. if( multipleSetFuncs.GetLength() > 1 )
  9325. {
  9326. asCString str;
  9327. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  9328. Error(str, node);
  9329. PrintMatchingFuncs(multipleSetFuncs, node);
  9330. return -1;
  9331. }
  9332. else
  9333. {
  9334. // The id may have changed
  9335. setId = multipleSetFuncs[0];
  9336. }
  9337. }
  9338. // Check for type compatibility between get and set accessor
  9339. if( getId && setId )
  9340. {
  9341. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  9342. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  9343. // It is permitted for a getter to return a handle and the setter to take a reference
  9344. int idx = (arg?1:0);
  9345. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  9346. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  9347. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  9348. {
  9349. asCString str;
  9350. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  9351. Error(str, node);
  9352. asCArray<int> funcs;
  9353. funcs.PushLast(getId);
  9354. funcs.PushLast(setId);
  9355. PrintMatchingFuncs(funcs, node);
  9356. return -1;
  9357. }
  9358. }
  9359. // Check if we are within one of the accessors
  9360. int realGetId = getId;
  9361. int realSetId = setId;
  9362. if( outFunc->objectType && isThisAccess )
  9363. {
  9364. // The property accessors would be virtual functions, so we need to find the real implementation
  9365. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  9366. if( getFunc &&
  9367. getFunc->funcType == asFUNC_VIRTUAL &&
  9368. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  9369. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  9370. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  9371. if( setFunc &&
  9372. setFunc->funcType == asFUNC_VIRTUAL &&
  9373. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  9374. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  9375. }
  9376. // Avoid recursive call, by not treating this as a property accessor call.
  9377. // This will also allow having the real property with the same name as the accessors.
  9378. if( (isThisAccess || outFunc->objectType == 0) &&
  9379. ((realGetId && realGetId == outFunc->id) ||
  9380. (realSetId && realSetId == outFunc->id)) )
  9381. {
  9382. getId = 0;
  9383. setId = 0;
  9384. }
  9385. // Check if the application has disabled script written property accessors
  9386. if( engine->ep.propertyAccessorMode == 1 )
  9387. {
  9388. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  9389. getId = 0;
  9390. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  9391. setId = 0;
  9392. }
  9393. if( getId || setId )
  9394. {
  9395. // Property accessors were found, but we don't know which is to be used yet, so
  9396. // we just prepare the bytecode for the method call, and then store the function ids
  9397. // so that the right one can be used when we get there.
  9398. ctx->property_get = getId;
  9399. ctx->property_set = setId;
  9400. if( ctx->type.dataType.IsObject() )
  9401. {
  9402. // If the object is read-only then we need to remember that
  9403. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  9404. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  9405. ctx->property_const = true;
  9406. else
  9407. ctx->property_const = false;
  9408. // If the object is a handle then we need to remember that
  9409. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  9410. ctx->property_ref = ctx->type.dataType.IsReference();
  9411. }
  9412. // The setter's parameter type is used as the property type,
  9413. // unless only the getter is available
  9414. asCDataType dt;
  9415. if( setId )
  9416. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  9417. else
  9418. dt = builder->GetFunctionDescription(getId)->returnType;
  9419. // Just change the type, the context must still maintain information
  9420. // about previous variable offset and the indicator of temporary variable.
  9421. int offset = ctx->type.stackOffset;
  9422. bool isTemp = ctx->type.isTemporary;
  9423. ctx->type.Set(dt);
  9424. ctx->type.stackOffset = (short)offset;
  9425. ctx->type.isTemporary = isTemp;
  9426. ctx->exprNode = node;
  9427. // Store the argument for later use
  9428. if( arg )
  9429. {
  9430. ctx->property_arg = asNEW(asSExprContext)(engine);
  9431. if( ctx->property_arg == 0 )
  9432. {
  9433. // Out of memory
  9434. return -1;
  9435. }
  9436. MergeExprBytecodeAndType(ctx->property_arg, arg);
  9437. }
  9438. return 1;
  9439. }
  9440. // No accessor was found
  9441. return 0;
  9442. }
  9443. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  9444. {
  9445. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  9446. if( !ctx->property_set )
  9447. {
  9448. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  9449. return -1;
  9450. }
  9451. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  9452. // Make sure the arg match the property
  9453. asCArray<int> funcs;
  9454. funcs.PushLast(ctx->property_set);
  9455. asCArray<asSExprContext *> args;
  9456. if( ctx->property_arg )
  9457. args.PushLast(ctx->property_arg);
  9458. args.PushLast(arg);
  9459. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  9460. if( funcs.GetLength() == 0 )
  9461. {
  9462. // MatchFunctions already reported the error
  9463. if( ctx->property_arg )
  9464. {
  9465. asDELETE(ctx->property_arg, asSExprContext);
  9466. ctx->property_arg = 0;
  9467. }
  9468. return -1;
  9469. }
  9470. if( func->objectType )
  9471. {
  9472. // Setup the context with the original type so the method call gets built correctly
  9473. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9474. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9475. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9476. // Don't allow the call if the object is read-only and the property accessor is not const
  9477. if( ctx->property_const && !func->isReadOnly )
  9478. {
  9479. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9480. asCArray<int> funcs;
  9481. funcs.PushLast(ctx->property_set);
  9482. PrintMatchingFuncs(funcs, node);
  9483. }
  9484. }
  9485. // Call the accessor
  9486. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  9487. ctx->property_get = 0;
  9488. ctx->property_set = 0;
  9489. if( ctx->property_arg )
  9490. {
  9491. asDELETE(ctx->property_arg, asSExprContext);
  9492. ctx->property_arg = 0;
  9493. }
  9494. return 0;
  9495. }
  9496. int asCCompiler::ProcessPropertyGetSetAccessor(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  9497. {
  9498. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  9499. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  9500. // to support value types, since it would be a single call
  9501. // Compound assignment for indexed property accessors is not supported yet
  9502. if( lctx->property_arg != 0 )
  9503. {
  9504. // Process the property to free the memory
  9505. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9506. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  9507. return -1;
  9508. }
  9509. // Compound assignments require both get and set accessors
  9510. if( lctx->property_set == 0 || lctx->property_get == 0 )
  9511. {
  9512. // Process the property to free the memory
  9513. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9514. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  9515. return -1;
  9516. }
  9517. // Property accessors on value types (or scoped references types) are not supported since
  9518. // it is not possible to guarantee that the object will stay alive between the two calls
  9519. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  9520. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  9521. {
  9522. // Process the property to free the memory
  9523. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9524. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  9525. return -1;
  9526. }
  9527. // Translate the compound assignment to the corresponding dual operator
  9528. switch( op )
  9529. {
  9530. case ttAddAssign: op = ttPlus; break;
  9531. case ttSubAssign: op = ttMinus; break;
  9532. case ttMulAssign: op = ttStar; break;
  9533. case ttDivAssign: op = ttSlash; break;
  9534. case ttModAssign: op = ttPercent; break;
  9535. case ttPowAssign: op = ttStarStar; break;
  9536. case ttAndAssign: op = ttAmp; break;
  9537. case ttOrAssign: op = ttBitOr; break;
  9538. case ttXorAssign: op = ttBitXor; break;
  9539. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  9540. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  9541. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  9542. default: op = ttUnrecognizedToken; break;
  9543. }
  9544. if( op == ttUnrecognizedToken )
  9545. {
  9546. // Shouldn't happen
  9547. asASSERT(false);
  9548. // Process the property to free the memory
  9549. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9550. return -1;
  9551. }
  9552. asSExprContext before(engine);
  9553. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  9554. {
  9555. // Keep a reference to the object in a local variable
  9556. before.bc.AddCode(&lctx->bc);
  9557. asUINT len = reservedVariables.GetLength();
  9558. rctx->bc.GetVarsUsed(reservedVariables);
  9559. before.bc.GetVarsUsed(reservedVariables);
  9560. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  9561. int offset = AllocateVariable(dt, true);
  9562. reservedVariables.SetLength(len);
  9563. before.type.SetVariable(dt, offset, true);
  9564. if( lctx->property_ref )
  9565. before.bc.Instr(asBC_RDSPtr);
  9566. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  9567. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  9568. before.bc.Instr(asBC_PopPtr);
  9569. if( lctx->type.isTemporary )
  9570. {
  9571. // Add the release of the temporary variable as a deferred expression
  9572. asSDeferredParam deferred;
  9573. deferred.origExpr = 0;
  9574. deferred.argInOutFlags = asTM_INREF;
  9575. deferred.argNode = 0;
  9576. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  9577. before.deferredParams.PushLast(deferred);
  9578. }
  9579. // Update the left expression to use the local variable
  9580. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  9581. lctx->type.stackOffset = (short)offset;
  9582. lctx->property_ref = true;
  9583. // Don't release the temporary variable too early
  9584. lctx->type.isTemporary = false;
  9585. ctx->bc.AddCode(&before.bc);
  9586. }
  9587. // Keep the original information on the property
  9588. asSExprContext llctx(engine);
  9589. llctx.type = lctx->type;
  9590. llctx.property_arg = lctx->property_arg;
  9591. llctx.property_const = lctx->property_const;
  9592. llctx.property_get = lctx->property_get;
  9593. llctx.property_handle = lctx->property_handle;
  9594. llctx.property_ref = lctx->property_ref;
  9595. llctx.property_set = lctx->property_set;
  9596. // Compile the dual operator using the get accessor
  9597. CompileOperator(errNode, lctx, rctx, ctx, op);
  9598. // If we made a local variable to hold the reference it must be reused
  9599. if( before.type.stackOffset )
  9600. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  9601. // Compile the assignment using the set accessor
  9602. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  9603. MergeExprBytecodeAndType(ctx, &llctx);
  9604. if( before.type.stackOffset )
  9605. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  9606. asASSERT( ctx->deferredParams.GetLength() == 0 );
  9607. ctx->deferredParams = before.deferredParams;
  9608. ProcessDeferredParams(ctx);
  9609. return 0;
  9610. }
  9611. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  9612. {
  9613. // If no property accessor has been prepared then don't do anything
  9614. if( !ctx->property_get && !ctx->property_set )
  9615. return;
  9616. if( !ctx->property_get )
  9617. {
  9618. // Raise error on missing accessor
  9619. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  9620. ctx->type.SetDummy();
  9621. return;
  9622. }
  9623. asCTypeInfo objType = ctx->type;
  9624. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  9625. // Make sure the arg match the property
  9626. asCArray<int> funcs;
  9627. funcs.PushLast(ctx->property_get);
  9628. asCArray<asSExprContext *> args;
  9629. if( ctx->property_arg )
  9630. args.PushLast(ctx->property_arg);
  9631. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  9632. if( funcs.GetLength() == 0 )
  9633. {
  9634. // MatchFunctions already reported the error
  9635. if( ctx->property_arg )
  9636. {
  9637. asDELETE(ctx->property_arg, asSExprContext);
  9638. ctx->property_arg = 0;
  9639. }
  9640. ctx->type.SetDummy();
  9641. return;
  9642. }
  9643. if( func->objectType )
  9644. {
  9645. // Setup the context with the original type so the method call gets built correctly
  9646. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9647. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9648. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9649. // Don't allow the call if the object is read-only and the property accessor is not const
  9650. if( ctx->property_const && !func->isReadOnly )
  9651. {
  9652. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9653. asCArray<int> funcs;
  9654. funcs.PushLast(ctx->property_get);
  9655. PrintMatchingFuncs(funcs, node);
  9656. }
  9657. }
  9658. // The explicit handle flag must be remembered
  9659. bool isExplicitHandle = ctx->type.isExplicitHandle;
  9660. // Call the accessor
  9661. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  9662. if( isExplicitHandle )
  9663. ctx->type.isExplicitHandle = true;
  9664. // Clear the property get/set ids
  9665. ctx->property_get = 0;
  9666. ctx->property_set = 0;
  9667. if( ctx->property_arg )
  9668. {
  9669. asDELETE(ctx->property_arg, asSExprContext);
  9670. ctx->property_arg = 0;
  9671. }
  9672. }
  9673. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  9674. {
  9675. // Don't allow any postfix operators on expressions that take address of class method
  9676. if( ctx->IsClassMethod() )
  9677. {
  9678. Error(TXT_INVALID_OP_ON_METHOD, node);
  9679. return -1;
  9680. }
  9681. // Don't allow any operators on void expressions
  9682. if( ctx->IsVoidExpression() )
  9683. {
  9684. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9685. return -1;
  9686. }
  9687. // Check if the variable is initialized (if it indeed is a variable)
  9688. IsVariableInitialized(&ctx->type, node);
  9689. int op = node->tokenType;
  9690. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9691. {
  9692. const char *opName = 0;
  9693. switch( op )
  9694. {
  9695. case ttInc: opName = "opPostInc"; break;
  9696. case ttDec: opName = "opPostDec"; break;
  9697. }
  9698. if( opName )
  9699. {
  9700. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9701. ProcessPropertyGetAccessor(ctx, node);
  9702. // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method
  9703. // Find the correct method
  9704. bool isConst = ctx->type.dataType.IsObjectConst();
  9705. asCArray<int> funcs;
  9706. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  9707. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9708. {
  9709. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9710. if( func->name == opName &&
  9711. func->parameterTypes.GetLength() == 0 &&
  9712. (!isConst || func->isReadOnly) )
  9713. {
  9714. funcs.PushLast(func->id);
  9715. }
  9716. }
  9717. // Did we find the method?
  9718. if( funcs.GetLength() == 1 )
  9719. {
  9720. asCArray<asSExprContext *> args;
  9721. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  9722. return 0;
  9723. }
  9724. else if( funcs.GetLength() == 0 )
  9725. {
  9726. asCString str;
  9727. str = asCString(opName) + "()";
  9728. if( isConst )
  9729. str += " const";
  9730. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9731. Error(str, node);
  9732. ctx->type.SetDummy();
  9733. return -1;
  9734. }
  9735. else if( funcs.GetLength() > 1 )
  9736. {
  9737. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9738. PrintMatchingFuncs(funcs, node);
  9739. ctx->type.SetDummy();
  9740. return -1;
  9741. }
  9742. }
  9743. }
  9744. else if( op == ttInc || op == ttDec )
  9745. {
  9746. // Make sure the reference isn't a temporary variable
  9747. if( ctx->type.isTemporary )
  9748. {
  9749. Error(TXT_REF_IS_TEMP, node);
  9750. return -1;
  9751. }
  9752. if( ctx->type.dataType.IsReadOnly() )
  9753. {
  9754. Error(TXT_REF_IS_READ_ONLY, node);
  9755. return -1;
  9756. }
  9757. if( ctx->property_get || ctx->property_set )
  9758. {
  9759. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  9760. return -1;
  9761. }
  9762. if( !ctx->type.isLValue )
  9763. {
  9764. Error(TXT_NOT_LVALUE, node);
  9765. return -1;
  9766. }
  9767. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9768. ConvertToReference(ctx);
  9769. else if( !ctx->type.dataType.IsReference() )
  9770. {
  9771. Error(TXT_NOT_VALID_REFERENCE, node);
  9772. return -1;
  9773. }
  9774. // Copy the value to a temp before changing it
  9775. ConvertToTempVariable(ctx);
  9776. asASSERT(!ctx->type.isLValue);
  9777. // Increment the value pointed to by the reference still in the register
  9778. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  9779. if( ctx->type.dataType.IsDoubleType() )
  9780. {
  9781. iInc = asBC_INCd;
  9782. iDec = asBC_DECd;
  9783. }
  9784. else if( ctx->type.dataType.IsFloatType() )
  9785. {
  9786. iInc = asBC_INCf;
  9787. iDec = asBC_DECf;
  9788. }
  9789. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  9790. {
  9791. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  9792. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  9793. {
  9794. iInc = asBC_INCi16;
  9795. iDec = asBC_DECi16;
  9796. }
  9797. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  9798. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  9799. {
  9800. iInc = asBC_INCi8;
  9801. iDec = asBC_DECi8;
  9802. }
  9803. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  9804. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  9805. {
  9806. iInc = asBC_INCi64;
  9807. iDec = asBC_DECi64;
  9808. }
  9809. }
  9810. else
  9811. {
  9812. Error(TXT_ILLEGAL_OPERATION, node);
  9813. return -1;
  9814. }
  9815. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  9816. }
  9817. else if( op == ttDot )
  9818. {
  9819. if( node->firstChild->nodeType == snIdentifier )
  9820. {
  9821. ProcessPropertyGetAccessor(ctx, node);
  9822. // Get the property name
  9823. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  9824. if( ctx->type.dataType.IsObject() )
  9825. {
  9826. // We need to look for get/set property accessors.
  9827. // If found, the context stores information on the get/set accessors
  9828. // until it is known which is to be used.
  9829. int r = 0;
  9830. if( node->next && node->next->tokenType == ttOpenBracket )
  9831. {
  9832. // The property accessor should take an index arg
  9833. asSExprContext dummyArg(engine);
  9834. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  9835. }
  9836. if( r == 0 )
  9837. r = FindPropertyAccessor(name, ctx, node, 0);
  9838. if( r != 0 )
  9839. return r;
  9840. if( !ctx->type.dataType.IsPrimitive() )
  9841. Dereference(ctx, true);
  9842. if( ctx->type.dataType.IsObjectHandle() )
  9843. {
  9844. // Convert the handle to a normal object
  9845. asCDataType dt = ctx->type.dataType;
  9846. dt.MakeHandle(false);
  9847. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  9848. // The handle may not have been an lvalue, but the dereferenced object is
  9849. ctx->type.isLValue = true;
  9850. }
  9851. bool isConst = ctx->type.dataType.IsObjectConst();
  9852. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  9853. if( prop )
  9854. {
  9855. // Is the property access allowed?
  9856. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  9857. {
  9858. asCString msg;
  9859. if( prop->isPrivate )
  9860. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  9861. else
  9862. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  9863. Error(msg, node);
  9864. }
  9865. // Put the offset on the stack
  9866. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  9867. if( prop->type.IsReference() )
  9868. ctx->bc.Instr(asBC_RDSPtr);
  9869. // Reference to primitive must be stored in the temp register
  9870. if( prop->type.IsPrimitive() )
  9871. {
  9872. ctx->bc.Instr(asBC_PopRPtr);
  9873. }
  9874. // Keep information about temporary variables as deferred expression
  9875. if( ctx->type.isTemporary )
  9876. {
  9877. // Add the release of this reference, as a deferred expression
  9878. asSDeferredParam deferred;
  9879. deferred.origExpr = 0;
  9880. deferred.argInOutFlags = asTM_INREF;
  9881. deferred.argNode = 0;
  9882. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9883. ctx->deferredParams.PushLast(deferred);
  9884. }
  9885. // Set the new type and make sure it is not treated as a variable anymore
  9886. ctx->type.dataType = prop->type;
  9887. ctx->type.dataType.MakeReference(true);
  9888. ctx->type.isVariable = false;
  9889. ctx->type.isTemporary = false;
  9890. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  9891. {
  9892. // Objects that are members are not references
  9893. ctx->type.dataType.MakeReference(false);
  9894. }
  9895. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  9896. }
  9897. else
  9898. {
  9899. // If the name is not a property, the compiler must check if the name matches
  9900. // a method, which can be used for constructing delegates
  9901. asIScriptFunction *func = 0;
  9902. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  9903. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9904. {
  9905. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  9906. {
  9907. func = engine->scriptFunctions[ot->methods[n]];
  9908. break;
  9909. }
  9910. }
  9911. if( func )
  9912. {
  9913. // An object method was found. Keep the name of the method in the expression, but
  9914. // don't actually modify the bytecode at this point since it is not yet known what
  9915. // the method will be used for, or even what overloaded method should be used.
  9916. ctx->methodName = name;
  9917. }
  9918. else
  9919. {
  9920. asCString str;
  9921. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  9922. Error(str, node);
  9923. return -1;
  9924. }
  9925. }
  9926. }
  9927. else
  9928. {
  9929. asCString str;
  9930. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  9931. Error(str, node);
  9932. return -1;
  9933. }
  9934. }
  9935. else
  9936. {
  9937. // Make sure it is an object we are accessing
  9938. if( !ctx->type.dataType.IsObject() )
  9939. {
  9940. asCString str;
  9941. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  9942. Error(str, node);
  9943. return -1;
  9944. }
  9945. // Process the get property accessor
  9946. ProcessPropertyGetAccessor(ctx, node);
  9947. // Compile function call
  9948. int r = CompileFunctionCall(node->firstChild, ctx, ctx->type.dataType.GetObjectType(), ctx->type.dataType.IsObjectConst());
  9949. if( r < 0 ) return r;
  9950. }
  9951. }
  9952. else if( op == ttOpenBracket )
  9953. {
  9954. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  9955. // then we should use that instead of processing it now. If the argument has already been
  9956. // evaluated, then we should process the property accessor as a get access now as the new
  9957. // index operator is on the result of that accessor.
  9958. asCString propertyName;
  9959. asSNameSpace *ns = 0;
  9960. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  9961. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  9962. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  9963. {
  9964. // Determine the name of the property accessor
  9965. asCScriptFunction *func = 0;
  9966. if( ctx->property_get )
  9967. func = builder->GetFunctionDescription(ctx->property_get);
  9968. else
  9969. func = builder->GetFunctionDescription(ctx->property_set);
  9970. propertyName = func->GetName();
  9971. propertyName = propertyName.SubString(4);
  9972. // Set the original type of the expression so we can re-evaluate the property accessor
  9973. if( func->objectType )
  9974. {
  9975. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9976. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9977. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9978. }
  9979. else
  9980. {
  9981. // Store the namespace where the function is declared
  9982. // so the same function can be found later
  9983. ctx->type.SetDummy();
  9984. ns = func->nameSpace;
  9985. }
  9986. ctx->property_get = ctx->property_set = 0;
  9987. if( ctx->property_arg )
  9988. {
  9989. asDELETE(ctx->property_arg, asSExprContext);
  9990. ctx->property_arg = 0;
  9991. }
  9992. }
  9993. else
  9994. {
  9995. if( !ctx->type.dataType.IsObject() )
  9996. {
  9997. asCString str;
  9998. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  9999. Error(str, node);
  10000. return -1;
  10001. }
  10002. ProcessPropertyGetAccessor(ctx, node);
  10003. }
  10004. // Compile the expression
  10005. bool isOK = true;
  10006. asCArray<asSExprContext *> args;
  10007. asCArray<asSNamedArgument> namedArgs;
  10008. asASSERT( node->firstChild->nodeType == snArgList );
  10009. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  10010. {
  10011. // Check for the existence of the opIndex method
  10012. bool lookForProperty = true;
  10013. if( propertyName == "" )
  10014. {
  10015. bool isConst = ctx->type.dataType.IsObjectConst();
  10016. asCObjectType *objectType = ctx->type.dataType.GetObjectType();
  10017. asCArray<int> funcs;
  10018. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  10019. if( funcs.GetLength() > 0 )
  10020. {
  10021. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  10022. lookForProperty = false;
  10023. // Determine which of opIndex methods that match
  10024. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  10025. if( funcs.GetLength() != 1 )
  10026. {
  10027. // The error has already been reported by MatchFunctions
  10028. isOK = false;
  10029. }
  10030. else
  10031. {
  10032. // Add the default values for arguments not explicitly supplied
  10033. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  10034. if( r == 0 )
  10035. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset);
  10036. else
  10037. isOK = false;
  10038. }
  10039. }
  10040. }
  10041. if( lookForProperty && isOK )
  10042. {
  10043. if( args.GetLength() != 1 )
  10044. {
  10045. // TODO: opIndex: Implement this
  10046. Error("Property accessor with index only support 1 index argument for now", node);
  10047. isOK = false;
  10048. }
  10049. Dereference(ctx, true);
  10050. asSExprContext lctx(engine);
  10051. MergeExprBytecodeAndType(&lctx, ctx);
  10052. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  10053. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  10054. if( r == 0 )
  10055. {
  10056. asCString str;
  10057. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10058. Error(str, node);
  10059. isOK = false;
  10060. }
  10061. else if( r < 0 )
  10062. isOK = false;
  10063. if( isOK )
  10064. MergeExprBytecodeAndType(ctx, &lctx);
  10065. }
  10066. }
  10067. else
  10068. isOK = false;
  10069. // Cleanup
  10070. for( asUINT n = 0; n < args.GetLength(); n++ )
  10071. if( args[n] )
  10072. {
  10073. asDELETE(args[n],asSExprContext);
  10074. }
  10075. if( !isOK )
  10076. return -1;
  10077. }
  10078. else if( op == ttOpenParanthesis )
  10079. {
  10080. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  10081. // Make sure the expression is a funcdef or an object that may have opCall methods
  10082. if( !ctx->type.dataType.GetFuncDef() && !ctx->type.dataType.IsObject() )
  10083. {
  10084. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  10085. return -1;
  10086. }
  10087. // Compile arguments
  10088. asCArray<asSExprContext *> args;
  10089. asCArray<asSNamedArgument> namedArgs;
  10090. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  10091. {
  10092. // Match arguments with the funcdef
  10093. asCArray<int> funcs;
  10094. if( ctx->type.dataType.GetFuncDef() )
  10095. {
  10096. funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
  10097. MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf(), &namedArgs);
  10098. }
  10099. else
  10100. {
  10101. bool isConst = ctx->type.dataType.IsObjectConst();
  10102. builder->GetObjectMethodDescriptions("opCall", ctx->type.dataType.GetObjectType(), funcs, isConst);
  10103. MatchFunctions(funcs, args, node, "opCall", &namedArgs, ctx->type.dataType.GetObjectType(), isConst);
  10104. }
  10105. if( funcs.GetLength() != 1 )
  10106. {
  10107. // The error was reported by MatchFunctions()
  10108. // Dummy value
  10109. ctx->type.SetDummy();
  10110. }
  10111. else
  10112. {
  10113. // Add the default values for arguments not explicitly supplied
  10114. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], ctx->type.dataType.GetObjectType(), &namedArgs);
  10115. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  10116. // is it enough to make sure it is in a local variable?
  10117. // For function pointer we must guarantee that the function is safe, i.e.
  10118. // by first storing the function pointer in a local variable (if it isn't already in one)
  10119. if( r == asSUCCESS )
  10120. {
  10121. Dereference(ctx, true);
  10122. if( ctx->type.dataType.GetFuncDef() )
  10123. {
  10124. if( !ctx->type.isVariable )
  10125. ConvertToVariable(ctx);
  10126. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  10127. ctx->bc.Instr(asBC_PopPtr);
  10128. }
  10129. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetFuncDef() ? 0 : ctx->type.dataType.GetObjectType(), args, node, false, 0, ctx->type.stackOffset);
  10130. }
  10131. }
  10132. }
  10133. else
  10134. ctx->type.SetDummy();
  10135. // Cleanup
  10136. for( asUINT n = 0; n < args.GetLength(); n++ )
  10137. if( args[n] )
  10138. {
  10139. asDELETE(args[n],asSExprContext);
  10140. }
  10141. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  10142. if( namedArgs[n].ctx )
  10143. {
  10144. asDELETE(namedArgs[n].ctx,asSExprContext);
  10145. }
  10146. }
  10147. return 0;
  10148. }
  10149. int asCCompiler::GetPrecedence(asCScriptNode *op)
  10150. {
  10151. // x ** y
  10152. // x * y, x / y, x % y
  10153. // x + y, x - y
  10154. // x <= y, x < y, x >= y, x > y
  10155. // x = =y, x != y, x xor y, x is y, x !is y
  10156. // x and y
  10157. // x or y
  10158. // The following are not used in this function,
  10159. // but should have lower precedence than the above
  10160. // x ? y : z
  10161. // x = y
  10162. // The expression term have the highest precedence
  10163. if( op->nodeType == snExprTerm )
  10164. return 1;
  10165. // Evaluate operators by token
  10166. int tokenType = op->tokenType;
  10167. if( tokenType == ttStarStar )
  10168. return 0;
  10169. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  10170. return -1;
  10171. if( tokenType == ttPlus || tokenType == ttMinus )
  10172. return -2;
  10173. if( tokenType == ttBitShiftLeft ||
  10174. tokenType == ttBitShiftRight ||
  10175. tokenType == ttBitShiftRightArith )
  10176. return -3;
  10177. if( tokenType == ttAmp )
  10178. return -4;
  10179. if( tokenType == ttBitXor )
  10180. return -5;
  10181. if( tokenType == ttBitOr )
  10182. return -6;
  10183. if( tokenType == ttLessThanOrEqual ||
  10184. tokenType == ttLessThan ||
  10185. tokenType == ttGreaterThanOrEqual ||
  10186. tokenType == ttGreaterThan )
  10187. return -7;
  10188. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  10189. return -8;
  10190. if( tokenType == ttAnd )
  10191. return -9;
  10192. if( tokenType == ttOr )
  10193. return -10;
  10194. // Unknown operator
  10195. asASSERT(false);
  10196. return 0;
  10197. }
  10198. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  10199. {
  10200. matches.SetLength(0);
  10201. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  10202. {
  10203. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  10204. // Does the function have arguments enough?
  10205. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  10206. continue;
  10207. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  10208. if( cost != -1 )
  10209. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  10210. }
  10211. return (asUINT)matches.GetLength();
  10212. }
  10213. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  10214. {
  10215. // void expressions can match any out parameter, but nothing else
  10216. if( argExpr->IsVoidExpression() )
  10217. {
  10218. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  10219. return 0;
  10220. return -1;
  10221. }
  10222. // Can we make the match by implicit conversion?
  10223. asSExprContext ti(engine);
  10224. ti.type = argExpr->type;
  10225. ti.methodName = argExpr->methodName;
  10226. ti.enumValue = argExpr->enumValue;
  10227. ti.exprNode = argExpr->exprNode;
  10228. if( argExpr->type.dataType.IsPrimitive() )
  10229. ti.type.dataType.MakeReference(false);
  10230. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  10231. // If the function parameter is an inout-reference then it must not be possible to call the
  10232. // function with an incorrect argument type, even though the type can normally be converted.
  10233. if( desc->parameterTypes[paramNum].IsReference() &&
  10234. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  10235. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  10236. {
  10237. // Observe, that the below checks are only necessary for when unsafe references have been
  10238. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  10239. // for these value types.
  10240. // Don't allow a primitive to be converted to a reference of another primitive type
  10241. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  10242. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  10243. {
  10244. asASSERT( engine->ep.allowUnsafeReferences );
  10245. return -1;
  10246. }
  10247. // Don't allow an enum to be converted to a reference of another enum type
  10248. if( desc->parameterTypes[paramNum].IsEnumType() &&
  10249. desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
  10250. {
  10251. asASSERT( engine->ep.allowUnsafeReferences );
  10252. return -1;
  10253. }
  10254. // Don't allow a non-handle expression to be converted to a reference to a handle
  10255. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  10256. !argExpr->type.dataType.IsObjectHandle() )
  10257. {
  10258. asASSERT( engine->ep.allowUnsafeReferences );
  10259. return -1;
  10260. }
  10261. // Don't allow a value type to be converted
  10262. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  10263. (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
  10264. {
  10265. asASSERT( engine->ep.allowUnsafeReferences );
  10266. return -1;
  10267. }
  10268. }
  10269. // How well does the argument match the function parameter?
  10270. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  10271. return cost;
  10272. // No match is available
  10273. return -1;
  10274. }
  10275. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  10276. {
  10277. // Reference parameters whose value won't be used don't evaluate the expression
  10278. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  10279. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  10280. {
  10281. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  10282. asSExprContext *orig = asNEW(asSExprContext)(engine);
  10283. if( orig == 0 )
  10284. {
  10285. // Out of memory
  10286. return;
  10287. }
  10288. MergeExprBytecodeAndType(orig, arg);
  10289. arg->origExpr = orig;
  10290. }
  10291. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  10292. // arg still holds the original expression for output parameters
  10293. ctx->bc.AddCode(&arg->bc);
  10294. }
  10295. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool isHandle, eTokenType token)
  10296. {
  10297. DetermineSingleFunc(lctx, node);
  10298. DetermineSingleFunc(rctx, node);
  10299. ctx->exprNode = node;
  10300. // What type of operator is it?
  10301. if( token == ttUnrecognizedToken )
  10302. token = node->tokenType;
  10303. if( token == ttUnrecognizedToken )
  10304. {
  10305. // This happens when the compiler is inferring an assignment
  10306. // operation from another action, for example in preparing a value
  10307. // as a function argument
  10308. token = ttAssignment;
  10309. }
  10310. // boolean operators are not overloadable
  10311. if( token == ttAnd ||
  10312. token == ttOr ||
  10313. token == ttXor )
  10314. return false;
  10315. // Dual operators can also be implemented as class methods
  10316. if( token == ttEqual ||
  10317. token == ttNotEqual )
  10318. {
  10319. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10320. // Find the matching opEquals method
  10321. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10322. if( r == 0 )
  10323. {
  10324. // Try again by switching the order of the operands
  10325. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10326. }
  10327. if( r == 1 )
  10328. {
  10329. if( token == ttNotEqual )
  10330. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10331. // Success, don't continue
  10332. return true;
  10333. }
  10334. else if( r < 0 )
  10335. {
  10336. // Compiler error, don't continue
  10337. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10338. return true;
  10339. }
  10340. }
  10341. if( token == ttEqual ||
  10342. token == ttNotEqual ||
  10343. token == ttLessThan ||
  10344. token == ttLessThanOrEqual ||
  10345. token == ttGreaterThan ||
  10346. token == ttGreaterThanOrEqual )
  10347. {
  10348. bool swappedOrder = false;
  10349. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10350. // Find the matching opCmp method
  10351. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  10352. if( r == 0 )
  10353. {
  10354. // Try again by switching the order of the operands
  10355. swappedOrder = true;
  10356. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  10357. }
  10358. if( r == 1 )
  10359. {
  10360. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10361. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  10362. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  10363. if( token == ttEqual )
  10364. ctx->bc.Instr(asBC_TZ);
  10365. else if( token == ttNotEqual )
  10366. ctx->bc.Instr(asBC_TNZ);
  10367. else if( (token == ttLessThan && !swappedOrder) ||
  10368. (token == ttGreaterThan && swappedOrder) )
  10369. ctx->bc.Instr(asBC_TS);
  10370. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  10371. (token == ttGreaterThanOrEqual && swappedOrder) )
  10372. ctx->bc.Instr(asBC_TNP);
  10373. else if( (token == ttGreaterThan && !swappedOrder) ||
  10374. (token == ttLessThan && swappedOrder) )
  10375. ctx->bc.Instr(asBC_TP);
  10376. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  10377. (token == ttLessThanOrEqual && swappedOrder) )
  10378. ctx->bc.Instr(asBC_TNS);
  10379. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10380. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  10381. // Success, don't continue
  10382. return true;
  10383. }
  10384. else if( r < 0 )
  10385. {
  10386. // Compiler error, don't continue
  10387. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10388. return true;
  10389. }
  10390. }
  10391. // The rest of the operators are not commutative, and doesn't require specific return type
  10392. const char *op = 0, *op_r = 0;
  10393. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  10394. {
  10395. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  10396. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  10397. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  10398. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  10399. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  10400. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  10401. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  10402. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  10403. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  10404. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  10405. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  10406. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  10407. }
  10408. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  10409. if( op && op_r )
  10410. {
  10411. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10412. // Find the matching operator method
  10413. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  10414. if( r == 0 )
  10415. {
  10416. // Try again by switching the order of the operands, and using the reversed operator
  10417. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  10418. }
  10419. if( r == 1 )
  10420. {
  10421. // Success, don't continue
  10422. return true;
  10423. }
  10424. else if( r < 0 )
  10425. {
  10426. // Compiler error, don't continue
  10427. ctx->type.SetDummy();
  10428. return true;
  10429. }
  10430. }
  10431. // Assignment operators
  10432. op = 0;
  10433. if( isHandle )
  10434. {
  10435. // Only asOBJ_ASHANDLE types can get here
  10436. asASSERT( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) );
  10437. asASSERT( token == ttAssignment );
  10438. if( token == ttAssignment )
  10439. op = "opHndlAssign";
  10440. }
  10441. else
  10442. {
  10443. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  10444. {
  10445. case ttAssignment: op = "opAssign"; break;
  10446. case ttAddAssign: op = "opAddAssign"; break;
  10447. case ttSubAssign: op = "opSubAssign"; break;
  10448. case ttMulAssign: op = "opMulAssign"; break;
  10449. case ttDivAssign: op = "opDivAssign"; break;
  10450. case ttModAssign: op = "opModAssign"; break;
  10451. case ttPowAssign: op = "opPowAssign"; break;
  10452. case ttOrAssign: op = "opOrAssign"; break;
  10453. case ttAndAssign: op = "opAndAssign"; break;
  10454. case ttXorAssign: op = "opXorAssign"; break;
  10455. case ttShiftLeftAssign: op = "opShlAssign"; break;
  10456. case ttShiftRightLAssign: op = "opShrAssign"; break;
  10457. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  10458. }
  10459. }
  10460. if( op )
  10461. {
  10462. if( builder->engine->ep.disallowValueAssignForRefType &&
  10463. lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  10464. {
  10465. if( token == ttAssignment )
  10466. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  10467. else
  10468. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  10469. // Set a dummy output
  10470. ctx->type.Set(lctx->type.dataType);
  10471. return true;
  10472. }
  10473. // TODO: Shouldn't accept const lvalue with the assignment operators
  10474. // Find the matching operator method
  10475. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  10476. if( r == 1 )
  10477. {
  10478. // Success, don't continue
  10479. return true;
  10480. }
  10481. else if( r < 0 )
  10482. {
  10483. // Compiler error, don't continue
  10484. ctx->type.SetDummy();
  10485. return true;
  10486. }
  10487. }
  10488. // No suitable operator was found
  10489. return false;
  10490. }
  10491. // Returns negative on compile error
  10492. // zero on no matching operator
  10493. // one on matching operator
  10494. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  10495. {
  10496. // Find the matching method
  10497. if( lctx->type.dataType.IsObject() &&
  10498. (!lctx->type.isExplicitHandle ||
  10499. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  10500. {
  10501. asUINT n;
  10502. // Is the left value a const?
  10503. bool isConst = lctx->type.dataType.IsObjectConst();
  10504. asCArray<int> funcs;
  10505. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  10506. for( n = 0; n < ot->methods.GetLength(); n++ )
  10507. {
  10508. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10509. asASSERT( func );
  10510. if( func && func->name == methodName &&
  10511. (!specificReturn || func->returnType == returnType) &&
  10512. func->parameterTypes.GetLength() == 1 &&
  10513. (!isConst || func->isReadOnly) )
  10514. {
  10515. // Make sure the method is accessible by the module
  10516. if( builder->module->accessMask & func->accessMask )
  10517. {
  10518. funcs.PushLast(func->id);
  10519. }
  10520. }
  10521. }
  10522. // Which is the best matching function?
  10523. asCArray<asSOverloadCandidate> tempFuncs;
  10524. MatchArgument(funcs, tempFuncs, rctx, 0);
  10525. // Find the lowest cost operator(s)
  10526. asCArray<int> ops;
  10527. asUINT bestCost = asUINT(-1);
  10528. for( n = 0; n < tempFuncs.GetLength(); ++n )
  10529. {
  10530. asUINT cost = tempFuncs[n].cost;
  10531. if( cost < bestCost )
  10532. {
  10533. ops.SetLength(0);
  10534. bestCost = cost;
  10535. }
  10536. if( cost == bestCost )
  10537. ops.PushLast(tempFuncs[n].funcId);
  10538. }
  10539. // If the object is not const, then we need to prioritize non-const methods
  10540. if( !isConst )
  10541. FilterConst(ops);
  10542. // Did we find an operator?
  10543. if( ops.GetLength() == 1 )
  10544. {
  10545. // Process the lctx expression as get accessor
  10546. ProcessPropertyGetAccessor(lctx, node);
  10547. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  10548. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  10549. asCArray<int> usedVars;
  10550. lctx->bc.GetVarsUsed(usedVars);
  10551. asUINT oldReservedVars = reservedVariables.GetLength();
  10552. for( asUINT n = 0; n < rctx->deferredParams.GetLength(); n++ )
  10553. {
  10554. if( rctx->deferredParams[n].argType.isTemporary &&
  10555. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset) )
  10556. {
  10557. if( reservedVariables.GetLength() == oldReservedVars )
  10558. reservedVariables.Concatenate(usedVars);
  10559. // Allocate a new variable for the deferred argument
  10560. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  10561. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  10562. rctx->deferredParams[n].argType.stackOffset = short(offset);
  10563. rctx->bc.ExchangeVar(oldVar, offset);
  10564. ReleaseTemporaryVariable(oldVar, 0);
  10565. }
  10566. }
  10567. reservedVariables.SetLength(oldReservedVars);
  10568. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  10569. asCArray<asSExprContext *> args;
  10570. args.PushLast(rctx);
  10571. MergeExprBytecode(ctx, lctx);
  10572. ctx->type = lctx->type;
  10573. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  10574. // Found matching operator
  10575. return 1;
  10576. }
  10577. else if( ops.GetLength() > 1 )
  10578. {
  10579. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10580. PrintMatchingFuncs(ops, node);
  10581. ctx->type.SetDummy();
  10582. // Compiler error
  10583. return -1;
  10584. }
  10585. }
  10586. // No matching operator
  10587. return 0;
  10588. }
  10589. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  10590. {
  10591. if( objectType )
  10592. Dereference(ctx, true);
  10593. // Store the expression node for error reporting
  10594. if( ctx->exprNode == 0 )
  10595. ctx->exprNode = node;
  10596. asCByteCode objBC(engine);
  10597. objBC.AddCode(&ctx->bc);
  10598. PrepareFunctionCall(funcId, &ctx->bc, args);
  10599. // Verify if any of the args variable offsets are used in the other code.
  10600. // If they are exchange the offset for a new one
  10601. asUINT n;
  10602. for( n = 0; n < args.GetLength(); n++ )
  10603. {
  10604. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  10605. {
  10606. // Release the current temporary variable
  10607. ReleaseTemporaryVariable(args[n]->type, 0);
  10608. asCDataType dt = args[n]->type.dataType;
  10609. dt.MakeReference(false);
  10610. int l = int(reservedVariables.GetLength());
  10611. objBC.GetVarsUsed(reservedVariables);
  10612. ctx->bc.GetVarsUsed(reservedVariables);
  10613. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  10614. reservedVariables.SetLength(l);
  10615. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  10616. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  10617. args[n]->type.stackOffset = (short)newOffset;
  10618. args[n]->type.isTemporary = true;
  10619. args[n]->type.isVariable = true;
  10620. }
  10621. }
  10622. // If the function will return a value type on the stack, then we must allocate space
  10623. // for that here and push the address on the stack as a hidden argument to the function
  10624. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  10625. if( func->DoesReturnOnStack() )
  10626. {
  10627. asASSERT(!useVariable);
  10628. useVariable = true;
  10629. stackOffset = AllocateVariable(func->returnType, true);
  10630. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  10631. }
  10632. ctx->bc.AddCode(&objBC);
  10633. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  10634. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  10635. }
  10636. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
  10637. {
  10638. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  10639. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  10640. {
  10641. Error(TXT_INVALID_OP_ON_METHOD, node);
  10642. return -1;
  10643. }
  10644. // Don't allow any operators on void expressions
  10645. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  10646. {
  10647. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10648. return -1;
  10649. }
  10650. if( op == ttUnrecognizedToken )
  10651. op = node->tokenType;
  10652. IsVariableInitialized(&lctx->type, node);
  10653. IsVariableInitialized(&rctx->type, node);
  10654. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  10655. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  10656. op == ttIs || op == ttNotIs )
  10657. {
  10658. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  10659. return 0;
  10660. }
  10661. else
  10662. {
  10663. // Compile an overloaded operator for the two operands
  10664. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx, false, op) )
  10665. return 0;
  10666. // If both operands are objects, then we shouldn't continue
  10667. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  10668. {
  10669. asCString str;
  10670. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10671. Error(str, node);
  10672. ctx->type.SetDummy();
  10673. return -1;
  10674. }
  10675. // Process the property get accessors (if any)
  10676. ProcessPropertyGetAccessor(lctx, node);
  10677. ProcessPropertyGetAccessor(rctx, node);
  10678. // Make sure we have two variables or constants
  10679. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  10680. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  10681. // Make sure lctx doesn't end up with a variable used in rctx
  10682. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10683. {
  10684. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  10685. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  10686. ReleaseTemporaryVariable(offset, 0);
  10687. }
  10688. // Math operators
  10689. // + - * / % ** += -= *= /= %= **=
  10690. if( op == ttPlus || op == ttAddAssign ||
  10691. op == ttMinus || op == ttSubAssign ||
  10692. op == ttStar || op == ttMulAssign ||
  10693. op == ttSlash || op == ttDivAssign ||
  10694. op == ttPercent || op == ttModAssign ||
  10695. op == ttStarStar || op == ttPowAssign )
  10696. {
  10697. CompileMathOperator(node, lctx, rctx, ctx, op);
  10698. return 0;
  10699. }
  10700. // Bitwise operators
  10701. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  10702. if( op == ttAmp || op == ttAndAssign ||
  10703. op == ttBitOr || op == ttOrAssign ||
  10704. op == ttBitXor || op == ttXorAssign ||
  10705. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  10706. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  10707. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10708. {
  10709. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  10710. return 0;
  10711. }
  10712. // Comparison operators
  10713. // == != < > <= >=
  10714. if( op == ttEqual || op == ttNotEqual ||
  10715. op == ttLessThan || op == ttLessThanOrEqual ||
  10716. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  10717. {
  10718. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  10719. return 0;
  10720. }
  10721. // Boolean operators
  10722. // && || ^^
  10723. if( op == ttAnd || op == ttOr || op == ttXor )
  10724. {
  10725. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  10726. return 0;
  10727. }
  10728. }
  10729. asASSERT(false);
  10730. return -1;
  10731. }
  10732. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  10733. {
  10734. int l = int(reservedVariables.GetLength());
  10735. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  10736. ConvertToTempVariable(ctx);
  10737. reservedVariables.SetLength(l);
  10738. }
  10739. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  10740. {
  10741. // This is only used for primitive types and null handles
  10742. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  10743. ConvertToVariable(ctx);
  10744. if( !ctx->type.isTemporary )
  10745. {
  10746. if( ctx->type.dataType.IsPrimitive() )
  10747. {
  10748. // Copy the variable to a temporary variable
  10749. int offset = AllocateVariable(ctx->type.dataType, true);
  10750. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10751. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  10752. else
  10753. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  10754. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10755. }
  10756. else
  10757. {
  10758. // We should never get here
  10759. asASSERT(false);
  10760. }
  10761. }
  10762. }
  10763. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  10764. {
  10765. // We should never get here while the context is still an unprocessed property accessor
  10766. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  10767. int offset;
  10768. if( !ctx->type.isVariable &&
  10769. (ctx->type.dataType.IsObjectHandle() ||
  10770. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  10771. {
  10772. offset = AllocateVariable(ctx->type.dataType, true);
  10773. if( ctx->type.IsNullConstant() )
  10774. {
  10775. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  10776. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  10777. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  10778. }
  10779. else
  10780. {
  10781. Dereference(ctx, true);
  10782. // Copy the object handle to a variable
  10783. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10784. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  10785. ctx->bc.Instr(asBC_PopPtr);
  10786. }
  10787. // As this is an object the reference must be placed on the stack
  10788. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10789. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10790. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10791. ctx->type.dataType.MakeHandle(true);
  10792. ctx->type.dataType.MakeReference(true);
  10793. }
  10794. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  10795. ctx->type.dataType.IsPrimitive() )
  10796. {
  10797. if( ctx->type.isConstant )
  10798. {
  10799. offset = AllocateVariable(ctx->type.dataType, true);
  10800. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10801. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  10802. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10803. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  10804. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10805. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  10806. else
  10807. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  10808. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10809. return;
  10810. }
  10811. else
  10812. {
  10813. asASSERT(ctx->type.dataType.IsPrimitive());
  10814. asASSERT(ctx->type.dataType.IsReference());
  10815. ctx->type.dataType.MakeReference(false);
  10816. offset = AllocateVariable(ctx->type.dataType, true);
  10817. // Read the value from the address in the register directly into the variable
  10818. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10819. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  10820. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10821. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  10822. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10823. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  10824. else
  10825. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  10826. }
  10827. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10828. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10829. }
  10830. }
  10831. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  10832. {
  10833. int l = int(reservedVariables.GetLength());
  10834. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  10835. ConvertToVariable(ctx);
  10836. reservedVariables.SetLength(l);
  10837. }
  10838. void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node)
  10839. {
  10840. asCArray<int> funcs;
  10841. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  10842. if( ot )
  10843. {
  10844. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  10845. {
  10846. // Consider only implicit casts
  10847. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10848. if( func->name == "opImplConv" &&
  10849. func->returnType.IsPrimitive() &&
  10850. func->parameterTypes.GetLength() == 0 )
  10851. funcs.PushLast(ot->methods[n]);
  10852. }
  10853. // Use the one with the highest precision
  10854. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  10855. while( funcs.GetLength() > 1 )
  10856. {
  10857. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  10858. int value1 = 11, value2 = 11;
  10859. for( asUINT i = 0; i < 10; i++ )
  10860. {
  10861. if( returnType == match[i] )
  10862. {
  10863. value1 = i;
  10864. break;
  10865. }
  10866. }
  10867. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  10868. {
  10869. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  10870. for( asUINT i = 0; i < 10; i++ )
  10871. {
  10872. if( returnType == match[i] )
  10873. {
  10874. value2 = i;
  10875. break;
  10876. }
  10877. }
  10878. if( value2 >= value1 )
  10879. {
  10880. // Remove this and continue searching
  10881. funcs.RemoveIndexUnordered(n--);
  10882. }
  10883. else
  10884. {
  10885. // Remove the first, and start over
  10886. funcs.RemoveIndexUnordered(0);
  10887. break;
  10888. }
  10889. }
  10890. }
  10891. // Do the conversion
  10892. if( funcs.GetLength() )
  10893. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  10894. }
  10895. }
  10896. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
  10897. {
  10898. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  10899. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  10900. // If either operand is a non-primitive then use the primitive type
  10901. if( !lctx->type.dataType.IsPrimitive() )
  10902. {
  10903. int l = int(reservedVariables.GetLength());
  10904. rctx->bc.GetVarsUsed(reservedVariables);
  10905. ImplicitConvObjectToBestMathType(lctx, node);
  10906. reservedVariables.SetLength(l);
  10907. }
  10908. if( !rctx->type.dataType.IsPrimitive() )
  10909. {
  10910. int l = int(reservedVariables.GetLength());
  10911. lctx->bc.GetVarsUsed(reservedVariables);
  10912. ImplicitConvObjectToBestMathType(rctx, node);
  10913. reservedVariables.SetLength(l);
  10914. }
  10915. // Both types must now be primitives. Implicitly convert them so they match
  10916. asCDataType to;
  10917. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  10918. to.SetTokenType(ttDouble);
  10919. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  10920. to.SetTokenType(ttFloat);
  10921. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10922. {
  10923. // Convert to int64 if both are signed or if one is non-constant and signed
  10924. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10925. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10926. to.SetTokenType(ttInt64);
  10927. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10928. to.SetTokenType(ttUInt64);
  10929. else
  10930. to.SetTokenType(ttInt64);
  10931. }
  10932. else
  10933. {
  10934. // Convert to int32 if both are signed or if one is non-constant and signed
  10935. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10936. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10937. to.SetTokenType(ttInt);
  10938. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10939. to.SetTokenType(ttUInt);
  10940. else
  10941. to.SetTokenType(ttInt);
  10942. }
  10943. // If doing an operation with double constant and float variable, the constant should be converted to float
  10944. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  10945. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  10946. to.SetTokenType(ttFloat);
  10947. if( op == ttUnrecognizedToken )
  10948. op = node->tokenType;
  10949. // If integer division is disabled, convert to floating-point
  10950. if( engine->ep.disableIntegerDivision &&
  10951. (op == ttSlash || op == ttDivAssign) &&
  10952. (to.IsIntegerType() || to.IsUnsignedType()) )
  10953. {
  10954. // Use double to avoid losing precision when dividing with 32bit ints
  10955. // For 64bit ints there is unfortunately no greater type so with those
  10956. // there is still a risk of loosing precision
  10957. to.SetTokenType(ttDouble);
  10958. }
  10959. // Do the actual conversion
  10960. int l = int(reservedVariables.GetLength());
  10961. rctx->bc.GetVarsUsed(reservedVariables);
  10962. lctx->bc.GetVarsUsed(reservedVariables);
  10963. if( lctx->type.dataType.IsReference() )
  10964. ConvertToVariable(lctx);
  10965. if( rctx->type.dataType.IsReference() )
  10966. ConvertToVariable(rctx);
  10967. if( to.IsPrimitive() )
  10968. {
  10969. // ttStarStar allows an integer, right-hand operand and a double
  10970. // left-hand operand.
  10971. if( (op == ttStarStar || op == ttPowAssign) &&
  10972. lctx->type.dataType.IsDoubleType() &&
  10973. (rctx->type.dataType.IsIntegerType() ||
  10974. rctx->type.dataType.IsUnsignedType()) )
  10975. {
  10976. to.SetTokenType(ttInt);
  10977. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  10978. to.SetTokenType(ttDouble);
  10979. }
  10980. else
  10981. {
  10982. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  10983. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  10984. }
  10985. }
  10986. reservedVariables.SetLength(l);
  10987. // Verify that the conversion was successful
  10988. if( !lctx->type.dataType.IsIntegerType() &&
  10989. !lctx->type.dataType.IsUnsignedType() &&
  10990. !lctx->type.dataType.IsFloatType() &&
  10991. !lctx->type.dataType.IsDoubleType() )
  10992. {
  10993. asCString str;
  10994. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10995. Error(str, node);
  10996. ctx->type.SetDummy();
  10997. return;
  10998. }
  10999. if( !rctx->type.dataType.IsIntegerType() &&
  11000. !rctx->type.dataType.IsUnsignedType() &&
  11001. !rctx->type.dataType.IsFloatType() &&
  11002. !rctx->type.dataType.IsDoubleType() )
  11003. {
  11004. asCString str;
  11005. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11006. Error(str, node);
  11007. ctx->type.SetDummy();
  11008. return;
  11009. }
  11010. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11011. // Verify if we are dividing with a constant zero
  11012. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  11013. (op == ttSlash || op == ttDivAssign ||
  11014. op == ttPercent || op == ttModAssign) )
  11015. {
  11016. Error(TXT_DIVIDE_BY_ZERO, node);
  11017. }
  11018. if( !isConstant )
  11019. {
  11020. ConvertToVariableNotIn(lctx, rctx);
  11021. ConvertToVariableNotIn(rctx, lctx);
  11022. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11023. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11024. if( op == ttAddAssign || op == ttSubAssign ||
  11025. op == ttMulAssign || op == ttDivAssign ||
  11026. op == ttModAssign || op == ttPowAssign )
  11027. {
  11028. // Merge the operands in the different order so that they are evaluated correctly
  11029. MergeExprBytecode(ctx, rctx);
  11030. MergeExprBytecode(ctx, lctx);
  11031. // We must not process the deferred parameters yet, as
  11032. // it may overwrite the lvalue kept in the register
  11033. }
  11034. else
  11035. {
  11036. MergeExprBytecode(ctx, lctx);
  11037. MergeExprBytecode(ctx, rctx);
  11038. ProcessDeferredParams(ctx);
  11039. }
  11040. asEBCInstr instruction = asBC_ADDi;
  11041. if( lctx->type.dataType.IsIntegerType() ||
  11042. lctx->type.dataType.IsUnsignedType() )
  11043. {
  11044. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11045. {
  11046. if( op == ttPlus || op == ttAddAssign )
  11047. instruction = asBC_ADDi;
  11048. else if( op == ttMinus || op == ttSubAssign )
  11049. instruction = asBC_SUBi;
  11050. else if( op == ttStar || op == ttMulAssign )
  11051. instruction = asBC_MULi;
  11052. else if( op == ttSlash || op == ttDivAssign )
  11053. {
  11054. if( lctx->type.dataType.IsIntegerType() )
  11055. instruction = asBC_DIVi;
  11056. else
  11057. instruction = asBC_DIVu;
  11058. }
  11059. else if( op == ttPercent || op == ttModAssign )
  11060. {
  11061. if( lctx->type.dataType.IsIntegerType() )
  11062. instruction = asBC_MODi;
  11063. else
  11064. instruction = asBC_MODu;
  11065. }
  11066. else if( op == ttStarStar || op == ttPowAssign )
  11067. {
  11068. if( lctx->type.dataType.IsIntegerType() )
  11069. instruction = asBC_POWi;
  11070. else
  11071. instruction = asBC_POWu;
  11072. }
  11073. }
  11074. else
  11075. {
  11076. if( op == ttPlus || op == ttAddAssign )
  11077. instruction = asBC_ADDi64;
  11078. else if( op == ttMinus || op == ttSubAssign )
  11079. instruction = asBC_SUBi64;
  11080. else if( op == ttStar || op == ttMulAssign )
  11081. instruction = asBC_MULi64;
  11082. else if( op == ttSlash || op == ttDivAssign )
  11083. {
  11084. if( lctx->type.dataType.IsIntegerType() )
  11085. instruction = asBC_DIVi64;
  11086. else
  11087. instruction = asBC_DIVu64;
  11088. }
  11089. else if( op == ttPercent || op == ttModAssign )
  11090. {
  11091. if( lctx->type.dataType.IsIntegerType() )
  11092. instruction = asBC_MODi64;
  11093. else
  11094. instruction = asBC_MODu64;
  11095. }
  11096. else if( op == ttStarStar || op == ttPowAssign )
  11097. {
  11098. if( lctx->type.dataType.IsIntegerType() )
  11099. instruction = asBC_POWi64;
  11100. else
  11101. instruction = asBC_POWu64;
  11102. }
  11103. }
  11104. }
  11105. else if( lctx->type.dataType.IsFloatType() )
  11106. {
  11107. if( op == ttPlus || op == ttAddAssign )
  11108. instruction = asBC_ADDf;
  11109. else if( op == ttMinus || op == ttSubAssign )
  11110. instruction = asBC_SUBf;
  11111. else if( op == ttStar || op == ttMulAssign )
  11112. instruction = asBC_MULf;
  11113. else if( op == ttSlash || op == ttDivAssign )
  11114. instruction = asBC_DIVf;
  11115. else if( op == ttPercent || op == ttModAssign )
  11116. instruction = asBC_MODf;
  11117. else if( op == ttStarStar || op == ttPowAssign )
  11118. instruction = asBC_POWf;
  11119. }
  11120. else if( lctx->type.dataType.IsDoubleType() )
  11121. {
  11122. if( rctx->type.dataType.IsIntegerType() )
  11123. {
  11124. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  11125. if( op == ttStarStar || op == ttPowAssign )
  11126. instruction = asBC_POWdi;
  11127. else
  11128. asASSERT(false); // Should not be possible
  11129. }
  11130. else
  11131. {
  11132. if( op == ttPlus || op == ttAddAssign )
  11133. instruction = asBC_ADDd;
  11134. else if( op == ttMinus || op == ttSubAssign )
  11135. instruction = asBC_SUBd;
  11136. else if( op == ttStar || op == ttMulAssign )
  11137. instruction = asBC_MULd;
  11138. else if( op == ttSlash || op == ttDivAssign )
  11139. instruction = asBC_DIVd;
  11140. else if( op == ttPercent || op == ttModAssign )
  11141. instruction = asBC_MODd;
  11142. else if( op == ttStarStar || op == ttPowAssign )
  11143. instruction = asBC_POWd;
  11144. }
  11145. }
  11146. else
  11147. {
  11148. // Shouldn't be possible
  11149. asASSERT(false);
  11150. }
  11151. // Do the operation
  11152. int a = AllocateVariable(lctx->type.dataType, true);
  11153. int b = lctx->type.stackOffset;
  11154. int c = rctx->type.stackOffset;
  11155. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11156. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11157. }
  11158. else
  11159. {
  11160. // Both values are constants
  11161. if( lctx->type.dataType.IsIntegerType() ||
  11162. lctx->type.dataType.IsUnsignedType() )
  11163. {
  11164. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11165. {
  11166. int v = 0;
  11167. if( op == ttPlus )
  11168. v = lctx->type.intValue + rctx->type.intValue;
  11169. else if( op == ttMinus )
  11170. v = lctx->type.intValue - rctx->type.intValue;
  11171. else if( op == ttStar )
  11172. v = lctx->type.intValue * rctx->type.intValue;
  11173. else if( op == ttSlash )
  11174. {
  11175. // TODO: Should probably report an error, rather than silently convert the value to 0
  11176. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  11177. v = 0;
  11178. else
  11179. if( lctx->type.dataType.IsIntegerType() )
  11180. v = lctx->type.intValue / rctx->type.intValue;
  11181. else
  11182. v = lctx->type.dwordValue / rctx->type.dwordValue;
  11183. }
  11184. else if( op == ttPercent )
  11185. {
  11186. // TODO: Should probably report an error, rather than silently convert the value to 0
  11187. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  11188. v = 0;
  11189. else
  11190. if( lctx->type.dataType.IsIntegerType() )
  11191. v = lctx->type.intValue % rctx->type.intValue;
  11192. else
  11193. v = lctx->type.dwordValue % rctx->type.dwordValue;
  11194. }
  11195. else if( op == ttStarStar )
  11196. {
  11197. bool isOverflow;
  11198. if( lctx->type.dataType.IsIntegerType() )
  11199. v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow);
  11200. else
  11201. v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow);
  11202. if( isOverflow )
  11203. Error(TXT_POW_OVERFLOW, node);
  11204. }
  11205. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11206. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  11207. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  11208. ctx->type.dataType.SetTokenType(ttInt);
  11209. }
  11210. else
  11211. {
  11212. asQWORD v = 0;
  11213. if( op == ttPlus )
  11214. v = lctx->type.qwordValue + rctx->type.qwordValue;
  11215. else if( op == ttMinus )
  11216. v = lctx->type.qwordValue - rctx->type.qwordValue;
  11217. else if( op == ttStar )
  11218. v = lctx->type.qwordValue * rctx->type.qwordValue;
  11219. else if( op == ttSlash )
  11220. {
  11221. // TODO: Should probably report an error, rather than silently convert the value to 0
  11222. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  11223. v = 0;
  11224. else
  11225. if( lctx->type.dataType.IsIntegerType() )
  11226. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  11227. else
  11228. v = lctx->type.qwordValue / rctx->type.qwordValue;
  11229. }
  11230. else if( op == ttPercent )
  11231. {
  11232. // TODO: Should probably report an error, rather than silently convert the value to 0
  11233. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  11234. v = 0;
  11235. else
  11236. if( lctx->type.dataType.IsIntegerType() )
  11237. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  11238. else
  11239. v = lctx->type.qwordValue % rctx->type.qwordValue;
  11240. }
  11241. else if( op == ttStarStar )
  11242. {
  11243. bool isOverflow;
  11244. if( lctx->type.dataType.IsIntegerType() )
  11245. v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow);
  11246. else
  11247. v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow);
  11248. if( isOverflow )
  11249. Error(TXT_POW_OVERFLOW, node);
  11250. }
  11251. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11252. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  11253. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  11254. ctx->type.dataType.SetTokenType(ttInt64);
  11255. }
  11256. }
  11257. else if( lctx->type.dataType.IsFloatType() )
  11258. {
  11259. float v = 0.0f;
  11260. if( op == ttPlus )
  11261. v = lctx->type.floatValue + rctx->type.floatValue;
  11262. else if( op == ttMinus )
  11263. v = lctx->type.floatValue - rctx->type.floatValue;
  11264. else if( op == ttStar )
  11265. v = lctx->type.floatValue * rctx->type.floatValue;
  11266. else if( op == ttSlash )
  11267. {
  11268. if( rctx->type.floatValue == 0 )
  11269. v = 0;
  11270. else
  11271. v = lctx->type.floatValue / rctx->type.floatValue;
  11272. }
  11273. else if( op == ttPercent )
  11274. {
  11275. if( rctx->type.floatValue == 0 )
  11276. v = 0;
  11277. else
  11278. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  11279. }
  11280. else if( op == ttStarStar )
  11281. {
  11282. v = pow(lctx->type.floatValue, rctx->type.floatValue);
  11283. if( v == HUGE_VAL )
  11284. Error(TXT_POW_OVERFLOW, node);
  11285. }
  11286. ctx->type.SetConstantF(lctx->type.dataType, v);
  11287. }
  11288. else if( lctx->type.dataType.IsDoubleType() )
  11289. {
  11290. double v = 0.0;
  11291. if( rctx->type.dataType.IsIntegerType() )
  11292. {
  11293. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  11294. if( op == ttStarStar || op == ttPowAssign )
  11295. {
  11296. v = pow(lctx->type.doubleValue, rctx->type.intValue);
  11297. if( v == HUGE_VAL )
  11298. Error(TXT_POW_OVERFLOW, node);
  11299. }
  11300. else
  11301. asASSERT(false); // Should not be possible
  11302. }
  11303. else
  11304. {
  11305. if( op == ttPlus )
  11306. v = lctx->type.doubleValue + rctx->type.doubleValue;
  11307. else if( op == ttMinus )
  11308. v = lctx->type.doubleValue - rctx->type.doubleValue;
  11309. else if( op == ttStar )
  11310. v = lctx->type.doubleValue * rctx->type.doubleValue;
  11311. else if( op == ttSlash )
  11312. {
  11313. if( rctx->type.doubleValue == 0 )
  11314. v = 0;
  11315. else
  11316. v = lctx->type.doubleValue / rctx->type.doubleValue;
  11317. }
  11318. else if( op == ttPercent )
  11319. {
  11320. if( rctx->type.doubleValue == 0 )
  11321. v = 0;
  11322. else
  11323. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  11324. }
  11325. else if( op == ttStarStar )
  11326. {
  11327. v = pow(lctx->type.doubleValue, rctx->type.doubleValue);
  11328. if( v == HUGE_VAL )
  11329. Error(TXT_POW_OVERFLOW, node);
  11330. }
  11331. }
  11332. ctx->type.SetConstantD(lctx->type.dataType, v);
  11333. }
  11334. else
  11335. {
  11336. // Shouldn't be possible
  11337. asASSERT(false);
  11338. }
  11339. }
  11340. }
  11341. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
  11342. {
  11343. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  11344. if( op == ttUnrecognizedToken )
  11345. op = node->tokenType;
  11346. if( op == ttAmp || op == ttAndAssign ||
  11347. op == ttBitOr || op == ttOrAssign ||
  11348. op == ttBitXor || op == ttXorAssign )
  11349. {
  11350. // Convert left hand operand to integer if it's not already one
  11351. asCDataType to;
  11352. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  11353. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11354. to.SetTokenType(ttInt64);
  11355. else
  11356. to.SetTokenType(ttInt);
  11357. // Do the actual conversion (keep sign/unsigned if possible)
  11358. int l = int(reservedVariables.GetLength());
  11359. rctx->bc.GetVarsUsed(reservedVariables);
  11360. if( lctx->type.dataType.IsUnsignedType() )
  11361. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  11362. else
  11363. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  11364. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11365. reservedVariables.SetLength(l);
  11366. // Verify that the conversion was successful
  11367. if( lctx->type.dataType != to )
  11368. {
  11369. asCString str;
  11370. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11371. Error(str, node);
  11372. }
  11373. // Convert right hand operand to same size as left hand
  11374. l = int(reservedVariables.GetLength());
  11375. lctx->bc.GetVarsUsed(reservedVariables);
  11376. if( rctx->type.dataType.IsUnsignedType() )
  11377. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  11378. else
  11379. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  11380. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11381. reservedVariables.SetLength(l);
  11382. if( rctx->type.dataType != to )
  11383. {
  11384. asCString str;
  11385. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11386. Error(str, node);
  11387. }
  11388. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11389. if( !isConstant )
  11390. {
  11391. ConvertToVariableNotIn(lctx, rctx);
  11392. ConvertToVariableNotIn(rctx, lctx);
  11393. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11394. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11395. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  11396. {
  11397. // Compound assignments execute the right hand value first
  11398. MergeExprBytecode(ctx, rctx);
  11399. MergeExprBytecode(ctx, lctx);
  11400. }
  11401. else
  11402. {
  11403. MergeExprBytecode(ctx, lctx);
  11404. MergeExprBytecode(ctx, rctx);
  11405. }
  11406. ProcessDeferredParams(ctx);
  11407. asEBCInstr instruction = asBC_BAND;
  11408. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11409. {
  11410. if( op == ttAmp || op == ttAndAssign )
  11411. instruction = asBC_BAND;
  11412. else if( op == ttBitOr || op == ttOrAssign )
  11413. instruction = asBC_BOR;
  11414. else if( op == ttBitXor || op == ttXorAssign )
  11415. instruction = asBC_BXOR;
  11416. }
  11417. else
  11418. {
  11419. if( op == ttAmp || op == ttAndAssign )
  11420. instruction = asBC_BAND64;
  11421. else if( op == ttBitOr || op == ttOrAssign )
  11422. instruction = asBC_BOR64;
  11423. else if( op == ttBitXor || op == ttXorAssign )
  11424. instruction = asBC_BXOR64;
  11425. }
  11426. // Do the operation
  11427. int a = AllocateVariable(lctx->type.dataType, true);
  11428. int b = lctx->type.stackOffset;
  11429. int c = rctx->type.stackOffset;
  11430. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11431. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11432. }
  11433. else
  11434. {
  11435. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11436. {
  11437. asQWORD v = 0;
  11438. if( op == ttAmp )
  11439. v = lctx->type.qwordValue & rctx->type.qwordValue;
  11440. else if( op == ttBitOr )
  11441. v = lctx->type.qwordValue | rctx->type.qwordValue;
  11442. else if( op == ttBitXor )
  11443. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  11444. // Remember the result
  11445. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11446. }
  11447. else
  11448. {
  11449. asDWORD v = 0;
  11450. if( op == ttAmp )
  11451. v = lctx->type.dwordValue & rctx->type.dwordValue;
  11452. else if( op == ttBitOr )
  11453. v = lctx->type.dwordValue | rctx->type.dwordValue;
  11454. else if( op == ttBitXor )
  11455. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  11456. // Remember the result
  11457. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11458. }
  11459. }
  11460. }
  11461. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  11462. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  11463. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11464. {
  11465. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  11466. if( lctx->type.dataType.IsObject() )
  11467. {
  11468. asCString str;
  11469. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11470. Error(str, node);
  11471. // Set an integer value and allow the compiler to continue
  11472. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  11473. return;
  11474. }
  11475. // Convert left hand operand to integer if it's not already one
  11476. asCDataType to = lctx->type.dataType;
  11477. if( lctx->type.dataType.IsUnsignedType() &&
  11478. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  11479. {
  11480. to = asCDataType::CreatePrimitive(ttUInt, false);
  11481. }
  11482. else if( !lctx->type.dataType.IsUnsignedType() )
  11483. {
  11484. asCDataType to;
  11485. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11486. to.SetTokenType(ttInt64);
  11487. else
  11488. to.SetTokenType(ttInt);
  11489. }
  11490. // Do the actual conversion
  11491. int l = int(reservedVariables.GetLength());
  11492. rctx->bc.GetVarsUsed(reservedVariables);
  11493. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11494. reservedVariables.SetLength(l);
  11495. // Verify that the conversion was successful
  11496. if( lctx->type.dataType != to )
  11497. {
  11498. asCString str;
  11499. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11500. Error(str, node);
  11501. }
  11502. // Right operand must be 32bit uint
  11503. l = int(reservedVariables.GetLength());
  11504. lctx->bc.GetVarsUsed(reservedVariables);
  11505. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  11506. reservedVariables.SetLength(l);
  11507. if( !rctx->type.dataType.IsUnsignedType() )
  11508. {
  11509. asCString str;
  11510. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  11511. Error(str, node);
  11512. }
  11513. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11514. if( !isConstant )
  11515. {
  11516. ConvertToVariableNotIn(lctx, rctx);
  11517. ConvertToVariableNotIn(rctx, lctx);
  11518. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11519. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11520. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  11521. {
  11522. // Compound assignments execute the right hand value first
  11523. MergeExprBytecode(ctx, rctx);
  11524. MergeExprBytecode(ctx, lctx);
  11525. }
  11526. else
  11527. {
  11528. MergeExprBytecode(ctx, lctx);
  11529. MergeExprBytecode(ctx, rctx);
  11530. }
  11531. ProcessDeferredParams(ctx);
  11532. asEBCInstr instruction = asBC_BSLL;
  11533. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11534. {
  11535. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  11536. instruction = asBC_BSLL;
  11537. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  11538. instruction = asBC_BSRL;
  11539. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11540. instruction = asBC_BSRA;
  11541. }
  11542. else
  11543. {
  11544. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  11545. instruction = asBC_BSLL64;
  11546. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  11547. instruction = asBC_BSRL64;
  11548. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11549. instruction = asBC_BSRA64;
  11550. }
  11551. // Do the operation
  11552. int a = AllocateVariable(lctx->type.dataType, true);
  11553. int b = lctx->type.stackOffset;
  11554. int c = rctx->type.stackOffset;
  11555. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11556. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11557. }
  11558. else
  11559. {
  11560. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11561. {
  11562. asDWORD v = 0;
  11563. if( op == ttBitShiftLeft )
  11564. v = lctx->type.dwordValue << rctx->type.dwordValue;
  11565. else if( op == ttBitShiftRight )
  11566. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  11567. else if( op == ttBitShiftRightArith )
  11568. v = lctx->type.intValue >> rctx->type.dwordValue;
  11569. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11570. }
  11571. else
  11572. {
  11573. asQWORD v = 0;
  11574. if( op == ttBitShiftLeft )
  11575. v = lctx->type.qwordValue << rctx->type.dwordValue;
  11576. else if( op == ttBitShiftRight )
  11577. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  11578. else if( op == ttBitShiftRightArith )
  11579. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  11580. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11581. }
  11582. }
  11583. }
  11584. }
  11585. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
  11586. {
  11587. // Both operands must be of the same type
  11588. // If either operand is a non-primitive then first convert them to the best number type
  11589. if( !lctx->type.dataType.IsPrimitive() )
  11590. {
  11591. int l = int(reservedVariables.GetLength());
  11592. rctx->bc.GetVarsUsed(reservedVariables);
  11593. ImplicitConvObjectToBestMathType(lctx, node);
  11594. reservedVariables.SetLength(l);
  11595. }
  11596. if( !rctx->type.dataType.IsPrimitive() )
  11597. {
  11598. int l = int(reservedVariables.GetLength());
  11599. lctx->bc.GetVarsUsed(reservedVariables);
  11600. ImplicitConvObjectToBestMathType(rctx, node);
  11601. reservedVariables.SetLength(l);
  11602. }
  11603. // Implicitly convert the operands to matching types
  11604. asCDataType to;
  11605. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  11606. to.SetTokenType(ttDouble);
  11607. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  11608. to.SetTokenType(ttFloat);
  11609. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11610. {
  11611. // Convert to int64 if both are signed or if one is non-constant and signed
  11612. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11613. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11614. to.SetTokenType(ttInt64);
  11615. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11616. to.SetTokenType(ttUInt64);
  11617. else
  11618. to.SetTokenType(ttInt64);
  11619. }
  11620. else
  11621. {
  11622. // Convert to int32 if both are signed or if one is non-constant and signed
  11623. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11624. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11625. to.SetTokenType(ttInt);
  11626. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11627. to.SetTokenType(ttUInt);
  11628. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  11629. to.SetTokenType(ttBool);
  11630. else
  11631. to.SetTokenType(ttInt);
  11632. }
  11633. // If doing an operation with double constant and float variable, the constant should be converted to float
  11634. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  11635. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  11636. to.SetTokenType(ttFloat);
  11637. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  11638. // Do we have a mismatch between the sign of the operand?
  11639. bool signMismatch = false;
  11640. for( int n = 0; !signMismatch && n < 2; n++ )
  11641. {
  11642. asSExprContext *op = n ? rctx : lctx;
  11643. if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  11644. {
  11645. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  11646. signMismatch = true;
  11647. if( op->type.isConstant )
  11648. {
  11649. if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
  11650. {
  11651. if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
  11652. signMismatch = false;
  11653. }
  11654. else
  11655. {
  11656. if( !(op->type.dwordValue & (1<<31)) )
  11657. signMismatch = false;
  11658. }
  11659. // It's not necessary to check for floats or double, because if
  11660. // it was then the types for the conversion will never be unsigned
  11661. }
  11662. }
  11663. }
  11664. // Check for signed/unsigned mismatch
  11665. if( signMismatch )
  11666. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  11667. // Attempt to resolve ambiguous enumerations
  11668. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  11669. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  11670. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  11671. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  11672. // Do the actual conversion
  11673. int l = int(reservedVariables.GetLength());
  11674. rctx->bc.GetVarsUsed(reservedVariables);
  11675. if( lctx->type.dataType.IsReference() )
  11676. ConvertToVariable(lctx);
  11677. if( rctx->type.dataType.IsReference() )
  11678. ConvertToVariable(rctx);
  11679. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  11680. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  11681. reservedVariables.SetLength(l);
  11682. // Verify that the conversion was successful
  11683. bool ok = true;
  11684. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  11685. {
  11686. asCString str;
  11687. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11688. Error(str, node);
  11689. ok = false;
  11690. }
  11691. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  11692. {
  11693. asCString str;
  11694. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11695. Error(str, node);
  11696. ok = false;
  11697. }
  11698. if( !ok )
  11699. {
  11700. // It wasn't possible to get two valid operands, so we just return
  11701. // a boolean result and let the compiler continue.
  11702. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11703. return;
  11704. }
  11705. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11706. if( op == ttUnrecognizedToken )
  11707. op = node->tokenType;
  11708. if( !isConstant )
  11709. {
  11710. if( to.IsBooleanType() )
  11711. {
  11712. if( op == ttEqual || op == ttNotEqual )
  11713. {
  11714. // Must convert to temporary variable, because we are changing the value before comparison
  11715. ConvertToTempVariableNotIn(lctx, rctx);
  11716. ConvertToTempVariableNotIn(rctx, lctx);
  11717. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11718. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11719. // Make sure they are equal if not false
  11720. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  11721. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  11722. MergeExprBytecode(ctx, lctx);
  11723. MergeExprBytecode(ctx, rctx);
  11724. ProcessDeferredParams(ctx);
  11725. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  11726. int b = lctx->type.stackOffset;
  11727. int c = rctx->type.stackOffset;
  11728. if( op == ttEqual )
  11729. {
  11730. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  11731. ctx->bc.Instr(asBC_TZ);
  11732. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11733. }
  11734. else if( op == ttNotEqual )
  11735. {
  11736. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  11737. ctx->bc.Instr(asBC_TNZ);
  11738. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11739. }
  11740. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11741. }
  11742. else
  11743. {
  11744. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  11745. Error(TXT_ILLEGAL_OPERATION, node);
  11746. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  11747. }
  11748. }
  11749. else
  11750. {
  11751. ConvertToVariableNotIn(lctx, rctx);
  11752. ConvertToVariableNotIn(rctx, lctx);
  11753. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11754. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11755. MergeExprBytecode(ctx, lctx);
  11756. MergeExprBytecode(ctx, rctx);
  11757. ProcessDeferredParams(ctx);
  11758. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  11759. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11760. iCmp = asBC_CMPi;
  11761. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11762. iCmp = asBC_CMPu;
  11763. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11764. iCmp = asBC_CMPi64;
  11765. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11766. iCmp = asBC_CMPu64;
  11767. else if( lctx->type.dataType.IsFloatType() )
  11768. iCmp = asBC_CMPf;
  11769. else if( lctx->type.dataType.IsDoubleType() )
  11770. iCmp = asBC_CMPd;
  11771. else
  11772. asASSERT(false);
  11773. if( op == ttEqual )
  11774. iT = asBC_TZ;
  11775. else if( op == ttNotEqual )
  11776. iT = asBC_TNZ;
  11777. else if( op == ttLessThan )
  11778. iT = asBC_TS;
  11779. else if( op == ttLessThanOrEqual )
  11780. iT = asBC_TNP;
  11781. else if( op == ttGreaterThan )
  11782. iT = asBC_TP;
  11783. else if( op == ttGreaterThanOrEqual )
  11784. iT = asBC_TNS;
  11785. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  11786. int b = lctx->type.stackOffset;
  11787. int c = rctx->type.stackOffset;
  11788. ctx->bc.InstrW_W(iCmp, b, c);
  11789. ctx->bc.Instr(iT);
  11790. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11791. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11792. }
  11793. }
  11794. else
  11795. {
  11796. if( to.IsBooleanType() )
  11797. {
  11798. if( op == ttEqual || op == ttNotEqual )
  11799. {
  11800. // Make sure they are equal if not false
  11801. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11802. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11803. asDWORD v = 0;
  11804. if( op == ttEqual )
  11805. {
  11806. v = lctx->type.intValue - rctx->type.intValue;
  11807. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11808. }
  11809. else if( op == ttNotEqual )
  11810. {
  11811. v = lctx->type.intValue - rctx->type.intValue;
  11812. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11813. }
  11814. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  11815. }
  11816. else
  11817. {
  11818. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  11819. Error(TXT_ILLEGAL_OPERATION, node);
  11820. }
  11821. }
  11822. else
  11823. {
  11824. int i = 0;
  11825. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11826. {
  11827. int v = lctx->type.intValue - rctx->type.intValue;
  11828. if( v < 0 ) i = -1;
  11829. if( v > 0 ) i = 1;
  11830. }
  11831. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11832. {
  11833. asDWORD v1 = lctx->type.dwordValue;
  11834. asDWORD v2 = rctx->type.dwordValue;
  11835. if( v1 < v2 ) i = -1;
  11836. if( v1 > v2 ) i = 1;
  11837. }
  11838. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11839. {
  11840. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  11841. if( v < 0 ) i = -1;
  11842. if( v > 0 ) i = 1;
  11843. }
  11844. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11845. {
  11846. asQWORD v1 = lctx->type.qwordValue;
  11847. asQWORD v2 = rctx->type.qwordValue;
  11848. if( v1 < v2 ) i = -1;
  11849. if( v1 > v2 ) i = 1;
  11850. }
  11851. else if( lctx->type.dataType.IsFloatType() )
  11852. {
  11853. float v = lctx->type.floatValue - rctx->type.floatValue;
  11854. if( v < 0 ) i = -1;
  11855. if( v > 0 ) i = 1;
  11856. }
  11857. else if( lctx->type.dataType.IsDoubleType() )
  11858. {
  11859. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  11860. if( v < 0 ) i = -1;
  11861. if( v > 0 ) i = 1;
  11862. }
  11863. if( op == ttEqual )
  11864. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11865. else if( op == ttNotEqual )
  11866. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11867. else if( op == ttLessThan )
  11868. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11869. else if( op == ttLessThanOrEqual )
  11870. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11871. else if( op == ttGreaterThan )
  11872. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11873. else if( op == ttGreaterThanOrEqual )
  11874. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11875. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  11876. }
  11877. }
  11878. }
  11879. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  11880. {
  11881. // Put the result on the stack
  11882. if( asReference )
  11883. {
  11884. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  11885. ctx->type.dataType.MakeReference(true);
  11886. }
  11887. else
  11888. {
  11889. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11890. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  11891. else
  11892. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  11893. }
  11894. }
  11895. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType op)
  11896. {
  11897. // Both operands must be booleans
  11898. asCDataType to;
  11899. to.SetTokenType(ttBool);
  11900. // Do the actual conversion
  11901. int l = int(reservedVariables.GetLength());
  11902. rctx->bc.GetVarsUsed(reservedVariables);
  11903. lctx->bc.GetVarsUsed(reservedVariables);
  11904. // Allow value types to be converted to bool using 'bool opImplConv()'
  11905. if( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  11906. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  11907. if( rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) )
  11908. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  11909. reservedVariables.SetLength(l);
  11910. // Verify that the conversion was successful
  11911. if( !lctx->type.dataType.IsBooleanType() )
  11912. {
  11913. asCString str;
  11914. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  11915. Error(str, node);
  11916. // Force the conversion to allow compilation to proceed
  11917. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11918. }
  11919. if( !rctx->type.dataType.IsBooleanType() )
  11920. {
  11921. asCString str;
  11922. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  11923. Error(str, node);
  11924. // Force the conversion to allow compilation to proceed
  11925. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11926. }
  11927. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11928. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  11929. // What kind of operator is it?
  11930. if( op == ttUnrecognizedToken )
  11931. op = node->tokenType;
  11932. if( op == ttXor )
  11933. {
  11934. if( !isConstant )
  11935. {
  11936. // Must convert to temporary variable, because we are changing the value before comparison
  11937. ConvertToTempVariableNotIn(lctx, rctx);
  11938. ConvertToTempVariableNotIn(rctx, lctx);
  11939. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11940. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11941. // Make sure they are equal if not false
  11942. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  11943. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  11944. MergeExprBytecode(ctx, lctx);
  11945. MergeExprBytecode(ctx, rctx);
  11946. ProcessDeferredParams(ctx);
  11947. int a = AllocateVariable(ctx->type.dataType, true);
  11948. int b = lctx->type.stackOffset;
  11949. int c = rctx->type.stackOffset;
  11950. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  11951. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11952. }
  11953. else
  11954. {
  11955. // Make sure they are equal if not false
  11956. #if AS_SIZEOF_BOOL == 1
  11957. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  11958. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  11959. asBYTE v = 0;
  11960. v = lctx->type.byteValue - rctx->type.byteValue;
  11961. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11962. ctx->type.isConstant = true;
  11963. ctx->type.byteValue = v;
  11964. #else
  11965. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11966. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11967. asDWORD v = 0;
  11968. v = lctx->type.intValue - rctx->type.intValue;
  11969. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11970. ctx->type.isConstant = true;
  11971. ctx->type.dwordValue = v;
  11972. #endif
  11973. }
  11974. }
  11975. else if( op == ttAnd ||
  11976. op == ttOr )
  11977. {
  11978. if( !isConstant )
  11979. {
  11980. // If or-operator and first value is 1 the second value shouldn't be calculated
  11981. // if and-operator and first value is 0 the second value shouldn't be calculated
  11982. ConvertToVariable(lctx);
  11983. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11984. MergeExprBytecode(ctx, lctx);
  11985. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11986. int label1 = nextLabel++;
  11987. int label2 = nextLabel++;
  11988. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  11989. ctx->bc.Instr(asBC_ClrHi);
  11990. if( op == ttAnd )
  11991. {
  11992. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  11993. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  11994. ctx->bc.InstrINT(asBC_JMP, label2);
  11995. }
  11996. else if( op == ttOr )
  11997. {
  11998. ctx->bc.InstrDWORD(asBC_JZ, label1);
  11999. #if AS_SIZEOF_BOOL == 1
  12000. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  12001. #else
  12002. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  12003. #endif
  12004. ctx->bc.InstrINT(asBC_JMP, label2);
  12005. }
  12006. ctx->bc.Label((short)label1);
  12007. ConvertToVariable(rctx);
  12008. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12009. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  12010. MergeExprBytecode(ctx, rctx);
  12011. ctx->bc.Label((short)label2);
  12012. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  12013. }
  12014. else
  12015. {
  12016. #if AS_SIZEOF_BOOL == 1
  12017. asBYTE v = 0;
  12018. if( op == ttAnd )
  12019. v = lctx->type.byteValue && rctx->type.byteValue;
  12020. else if( op == ttOr )
  12021. v = lctx->type.byteValue || rctx->type.byteValue;
  12022. // Remember the result
  12023. ctx->type.isConstant = true;
  12024. ctx->type.byteValue = v;
  12025. #else
  12026. asDWORD v = 0;
  12027. if( op == ttAnd )
  12028. v = lctx->type.dwordValue && rctx->type.dwordValue;
  12029. else if( op == ttOr )
  12030. v = lctx->type.dwordValue || rctx->type.dwordValue;
  12031. // Remember the result
  12032. ctx->type.isConstant = true;
  12033. ctx->type.dwordValue = v;
  12034. #endif
  12035. }
  12036. }
  12037. }
  12038. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, eTokenType opToken)
  12039. {
  12040. // Process the property accessor as get
  12041. ProcessPropertyGetAccessor(lctx, node);
  12042. ProcessPropertyGetAccessor(rctx, node);
  12043. DetermineSingleFunc(lctx, node);
  12044. DetermineSingleFunc(rctx, node);
  12045. // Make sure lctx doesn't end up with a variable used in rctx
  12046. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  12047. {
  12048. asCArray<int> vars;
  12049. rctx->bc.GetVarsUsed(vars);
  12050. int offset = AllocateVariable(lctx->type.dataType, true);
  12051. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  12052. ReleaseTemporaryVariable(offset, 0);
  12053. }
  12054. if( opToken == ttUnrecognizedToken )
  12055. opToken = node->tokenType;
  12056. // Warn if not both operands are explicit handles or null handles
  12057. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  12058. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  12059. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  12060. {
  12061. Warning(TXT_HANDLE_COMPARISON, node);
  12062. }
  12063. // If one of the operands is a value type used as handle, we should look for the opEquals method
  12064. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  12065. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  12066. (opToken == ttEqual || opToken == ttIs ||
  12067. opToken == ttNotEqual || opToken == ttNotIs) )
  12068. {
  12069. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  12070. // Find the matching opEquals method
  12071. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  12072. if( r == 0 )
  12073. {
  12074. // Try again by switching the order of the operands
  12075. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  12076. }
  12077. if( r == 1 )
  12078. {
  12079. if( opToken == ttNotEqual || opToken == ttNotIs )
  12080. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  12081. // Success, don't continue
  12082. return;
  12083. }
  12084. else if( r == 0 )
  12085. {
  12086. // Couldn't find opEquals method
  12087. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  12088. }
  12089. // Compiler error, don't continue
  12090. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12091. return;
  12092. }
  12093. // Implicitly convert null to the other type
  12094. asCDataType to;
  12095. if( lctx->type.IsNullConstant() )
  12096. to = rctx->type.dataType;
  12097. else if( rctx->type.IsNullConstant() )
  12098. to = lctx->type.dataType;
  12099. else
  12100. {
  12101. // Find a common base type
  12102. asSExprContext tmp(engine);
  12103. tmp.type = rctx->type;
  12104. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  12105. if( tmp.type.dataType.GetObjectType() == lctx->type.dataType.GetObjectType() )
  12106. to = lctx->type.dataType;
  12107. else
  12108. to = rctx->type.dataType;
  12109. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  12110. to.MakeHandleToConst(true);
  12111. }
  12112. // Need to pop the value if it is a null constant
  12113. if( lctx->type.IsNullConstant() )
  12114. lctx->bc.Instr(asBC_PopPtr);
  12115. if( rctx->type.IsNullConstant() )
  12116. rctx->bc.Instr(asBC_PopPtr);
  12117. // Convert both sides to explicit handles
  12118. to.MakeHandle(true);
  12119. to.MakeReference(false);
  12120. if( !to.IsObjectHandle() )
  12121. {
  12122. // Compiler error, don't continue
  12123. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  12124. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12125. return;
  12126. }
  12127. // Do the conversion
  12128. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12129. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12130. // Both operands must be of the same type
  12131. // Verify that the conversion was successful
  12132. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  12133. {
  12134. asCString str;
  12135. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12136. Error(str, node);
  12137. }
  12138. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  12139. {
  12140. asCString str;
  12141. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12142. Error(str, node);
  12143. }
  12144. // Make sure it really is handles that are being compared
  12145. if( !lctx->type.dataType.IsObjectHandle() )
  12146. {
  12147. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  12148. }
  12149. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  12150. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  12151. {
  12152. // Make sure handles received as parameters by reference are copied to a local variable before the
  12153. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  12154. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  12155. lctx->type.isVariable = false;
  12156. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  12157. rctx->type.isVariable = false;
  12158. // TODO: runtime optimize: don't do REFCPY if not necessary
  12159. ConvertToVariableNotIn(lctx, rctx);
  12160. ConvertToVariable(rctx);
  12161. // Pop the pointers from the stack as they will not be used
  12162. lctx->bc.Instr(asBC_PopPtr);
  12163. rctx->bc.Instr(asBC_PopPtr);
  12164. MergeExprBytecode(ctx, lctx);
  12165. MergeExprBytecode(ctx, rctx);
  12166. int a = AllocateVariable(ctx->type.dataType, true);
  12167. int b = lctx->type.stackOffset;
  12168. int c = rctx->type.stackOffset;
  12169. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  12170. if( opToken == ttEqual || opToken == ttIs )
  12171. ctx->bc.Instr(asBC_TZ);
  12172. else if( opToken == ttNotEqual || opToken == ttNotIs )
  12173. ctx->bc.Instr(asBC_TNZ);
  12174. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12175. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12176. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  12177. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  12178. ProcessDeferredParams(ctx);
  12179. }
  12180. else
  12181. {
  12182. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12183. Error(TXT_ILLEGAL_OPERATION, node);
  12184. }
  12185. }
  12186. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  12187. {
  12188. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  12189. // A shared object may not call non-shared functions
  12190. if( outFunc->IsShared() && !descr->IsShared() )
  12191. {
  12192. asCString msg;
  12193. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  12194. Error(msg, ctx->exprNode);
  12195. }
  12196. // Check if the function is private or protected
  12197. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  12198. {
  12199. asCString msg;
  12200. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  12201. Error(msg, ctx->exprNode);
  12202. }
  12203. else if( descr->isProtected &&
  12204. !(descr->GetObjectType() == outFunc->GetObjectType() ||
  12205. (outFunc->GetObjectType() && outFunc->GetObjectType()->DerivesFrom(descr->GetObjectType()))) )
  12206. {
  12207. asCString msg;
  12208. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  12209. Error(msg, ctx->exprNode);
  12210. }
  12211. int argSize = descr->GetSpaceNeededForArguments();
  12212. // If we're calling a class method we must make sure the object is guaranteed to stay
  12213. // alive throughout the call by holding on to a reference in a local variable. This must
  12214. // be done for any methods that return references, and any calls on script objects.
  12215. // Application registered objects are assumed to know to keep themselves alive even
  12216. // if the method doesn't return a refernce.
  12217. if( descr->objectType &&
  12218. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  12219. (descr->returnType.IsReference() || (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  12220. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  12221. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  12222. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  12223. {
  12224. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  12225. // local variable and then refer to the same for each call. An alias for the global variable
  12226. // should be stored in the variable scope so that the compiler can find it. For loops and
  12227. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  12228. // higher scope to increase the probability of re-use.
  12229. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  12230. int tempRef = AllocateVariable(ctx->type.dataType, true);
  12231. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  12232. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  12233. // Add the release of this reference as a deferred expression
  12234. asSDeferredParam deferred;
  12235. deferred.origExpr = 0;
  12236. deferred.argInOutFlags = asTM_INREF;
  12237. deferred.argNode = 0;
  12238. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  12239. ctx->deferredParams.PushLast(deferred);
  12240. // Forget the current type
  12241. ctx->type.SetDummy();
  12242. }
  12243. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  12244. if( descr->DoesReturnOnStack() && !useVariable )
  12245. {
  12246. useVariable = true;
  12247. varOffset = AllocateVariable(descr->returnType, true);
  12248. // Push the pointer to the pre-allocated space for the return value
  12249. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  12250. if( descr->objectType )
  12251. {
  12252. // The object pointer is already on the stack, but should be the top
  12253. // one, so we need to swap the pointers in order to get the correct
  12254. ctx->bc.Instr(asBC_SwapPtr);
  12255. }
  12256. }
  12257. if( isConstructor )
  12258. {
  12259. // Sometimes the value types are allocated on the heap,
  12260. // which is when this way of constructing them is used.
  12261. asASSERT(useVariable == false);
  12262. if( (objType->flags & asOBJ_TEMPLATE) )
  12263. {
  12264. asASSERT( descr->funcType == asFUNC_SCRIPT );
  12265. // Find the id of the real constructor and not the generated stub
  12266. asUINT id = 0;
  12267. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  12268. while( bc )
  12269. {
  12270. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  12271. {
  12272. id = asBC_INTARG(bc);
  12273. break;
  12274. }
  12275. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  12276. }
  12277. asASSERT( id );
  12278. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  12279. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  12280. }
  12281. else
  12282. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  12283. // The instruction has already moved the returned object to the variable
  12284. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  12285. ctx->type.isLValue = false;
  12286. // Clean up arguments
  12287. if( args )
  12288. AfterFunctionCall(funcId, *args, ctx, false);
  12289. ProcessDeferredParams(ctx);
  12290. return;
  12291. }
  12292. else
  12293. {
  12294. if( descr->objectType )
  12295. argSize += AS_PTR_SIZE;
  12296. // If the function returns an object by value the address of the location
  12297. // where the value should be stored is passed as an argument too
  12298. if( descr->DoesReturnOnStack() )
  12299. argSize += AS_PTR_SIZE;
  12300. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  12301. // should be made with asBC_CALL as it is faster. Examples where this
  12302. // is known is for example finalled methods where the class doesn't derive
  12303. // from any other, or even non-finalled methods but where it is known
  12304. // at compile time the true type of the object. The first should be
  12305. // quite easy to determine, but the latter will be quite complex and possibly
  12306. // not worth it.
  12307. if( descr->funcType == asFUNC_IMPORTED )
  12308. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  12309. // TODO: Maybe we need two different byte codes
  12310. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  12311. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  12312. else if( descr->funcType == asFUNC_SCRIPT )
  12313. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  12314. else if( descr->funcType == asFUNC_SYSTEM )
  12315. {
  12316. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  12317. // type &obj::func(int)
  12318. // type &obj::func(uint)
  12319. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  12320. descr->parameterTypes.GetLength() == 1 &&
  12321. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  12322. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  12323. !descr->parameterTypes[0].IsReference() )
  12324. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  12325. else
  12326. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  12327. }
  12328. else if( descr->funcType == asFUNC_FUNCDEF )
  12329. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  12330. }
  12331. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  12332. {
  12333. int returnOffset = 0;
  12334. asCTypeInfo tmpExpr = ctx->type;
  12335. if( descr->DoesReturnOnStack() )
  12336. {
  12337. asASSERT( useVariable );
  12338. // The variable was allocated before the function was called
  12339. returnOffset = varOffset;
  12340. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  12341. // The variable was initialized by the function, so we need to mark it as initialized here
  12342. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  12343. }
  12344. else
  12345. {
  12346. if( useVariable )
  12347. {
  12348. // Use the given variable
  12349. returnOffset = varOffset;
  12350. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  12351. }
  12352. else
  12353. {
  12354. // Allocate a temporary variable for the returned object
  12355. // The returned object will actually be allocated on the heap, so
  12356. // we must force the allocation of the variable to do the same
  12357. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  12358. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  12359. }
  12360. // Move the pointer from the object register to the temporary variable
  12361. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  12362. }
  12363. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  12364. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  12365. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  12366. // Clean up arguments
  12367. if( args )
  12368. AfterFunctionCall(funcId, *args, ctx, false);
  12369. ProcessDeferredParams(ctx);
  12370. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  12371. }
  12372. else if( descr->returnType.IsReference() )
  12373. {
  12374. asASSERT(useVariable == false);
  12375. // We cannot clean up the arguments yet, because the
  12376. // reference might be pointing to one of them.
  12377. if( args )
  12378. AfterFunctionCall(funcId, *args, ctx, true);
  12379. // Do not process the output parameters yet, because it
  12380. // might invalidate the returned reference
  12381. // If the context holds a variable that needs cleanup
  12382. // store it as a deferred parameter so it will be cleaned up
  12383. // afterwards.
  12384. if( ctx->type.isTemporary )
  12385. {
  12386. asSDeferredParam defer;
  12387. defer.argNode = 0;
  12388. defer.argType = ctx->type;
  12389. defer.argInOutFlags = asTM_INOUTREF;
  12390. defer.origExpr = 0;
  12391. ctx->deferredParams.PushLast(defer);
  12392. }
  12393. ctx->type.Set(descr->returnType);
  12394. if( !descr->returnType.IsPrimitive() )
  12395. {
  12396. ctx->bc.Instr(asBC_PshRPtr);
  12397. if( descr->returnType.IsObject() &&
  12398. !descr->returnType.IsObjectHandle() )
  12399. {
  12400. // We are getting the pointer to the object
  12401. // not a pointer to a object variable
  12402. ctx->type.dataType.MakeReference(false);
  12403. }
  12404. }
  12405. // A returned reference can be used as lvalue
  12406. ctx->type.isLValue = true;
  12407. }
  12408. else
  12409. {
  12410. asASSERT(useVariable == false);
  12411. asCTypeInfo tmpExpr = ctx->type;
  12412. if( descr->returnType.GetSizeInMemoryBytes() )
  12413. {
  12414. // Allocate a temporary variable to hold the value, but make sure
  12415. // the temporary variable isn't used in any of the deferred arguments
  12416. int l = int(reservedVariables.GetLength());
  12417. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  12418. {
  12419. asSExprContext *expr = (*args)[n]->origExpr;
  12420. if( expr )
  12421. expr->bc.GetVarsUsed(reservedVariables);
  12422. }
  12423. int offset = AllocateVariable(descr->returnType, true);
  12424. reservedVariables.SetLength(l);
  12425. ctx->type.SetVariable(descr->returnType, offset, true);
  12426. // Move the value from the return register to the variable
  12427. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  12428. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  12429. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  12430. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  12431. }
  12432. else
  12433. ctx->type.Set(descr->returnType);
  12434. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  12435. ctx->type.isLValue = false;
  12436. // Clean up arguments
  12437. if( args )
  12438. AfterFunctionCall(funcId, *args, ctx, false);
  12439. ProcessDeferredParams(ctx);
  12440. }
  12441. }
  12442. // This only merges the bytecode, but doesn't modify the type of the final context
  12443. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  12444. {
  12445. before->bc.AddCode(&after->bc);
  12446. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  12447. {
  12448. before->deferredParams.PushLast(after->deferredParams[n]);
  12449. after->deferredParams[n].origExpr = 0;
  12450. }
  12451. after->deferredParams.SetLength(0);
  12452. }
  12453. // This merges both bytecode and the type of the final context
  12454. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  12455. {
  12456. MergeExprBytecode(before, after);
  12457. before->Merge(after);
  12458. }
  12459. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  12460. {
  12461. if( funcs.GetLength() == 0 ) return;
  12462. // This is only done for object methods
  12463. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  12464. if( desc->objectType == 0 ) return;
  12465. // Check if there are any non-const matches
  12466. asUINT n;
  12467. bool foundNonConst = false;
  12468. for( n = 0; n < funcs.GetLength(); n++ )
  12469. {
  12470. desc = builder->GetFunctionDescription(funcs[n]);
  12471. if( desc->isReadOnly != removeConst )
  12472. {
  12473. foundNonConst = true;
  12474. break;
  12475. }
  12476. }
  12477. if( foundNonConst )
  12478. {
  12479. // Remove all const methods
  12480. for( n = 0; n < funcs.GetLength(); n++ )
  12481. {
  12482. desc = builder->GetFunctionDescription(funcs[n]);
  12483. if( desc->isReadOnly == removeConst )
  12484. {
  12485. if( n == funcs.GetLength() - 1 )
  12486. funcs.PopLast();
  12487. else
  12488. funcs[n] = funcs.PopLast();
  12489. n--;
  12490. }
  12491. }
  12492. }
  12493. }
  12494. END_AS_NAMESPACE
  12495. #endif // AS_NO_COMPILER