as_compiler.cpp 433 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2014 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. nextLabel = 0;
  88. breakLabels.SetLength(0);
  89. continueLabels.SetLength(0);
  90. byteCode.ClearAll();
  91. }
  92. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  93. {
  94. Reset(builder, script, outFunc);
  95. m_classDecl = classDecl;
  96. // Insert a JitEntry at the start of the function for JIT compilers
  97. byteCode.InstrPTR(asBC_JitEntry, 0);
  98. // Add a variable scope that might be needed to declare dummy variables
  99. // in case the member initialization refers to undefined symbols.
  100. AddVariableScope();
  101. // Initialize the class members that have no explicit expression first. This will allow the
  102. // base class' constructor to access these members without worry they will be uninitialized.
  103. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  104. CompileMemberInitialization(&byteCode, true);
  105. // If the class is derived from another, then the base class' default constructor must be called
  106. if( outFunc->objectType->derivedFrom )
  107. {
  108. // Make sure the base class really has a default constructor
  109. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  110. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node);
  111. // Call the base class' default constructor
  112. byteCode.InstrSHORT(asBC_PSF, 0);
  113. byteCode.Instr(asBC_RDSPtr);
  114. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  115. }
  116. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  117. // to access the base class members without worry they will be uninitialized
  118. CompileMemberInitialization(&byteCode, false);
  119. byteCode.OptimizeLocally(tempVariableOffsets);
  120. // If there are compile errors, there is no reason to build the final code
  121. if( hasCompileErrors )
  122. return -1;
  123. // Pop the object pointer from the stack
  124. byteCode.Ret(AS_PTR_SIZE);
  125. // Count total variable size
  126. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  127. outFunc->scriptData->variableSpace = varSize;
  128. FinalizeFunction();
  129. #ifdef AS_DEBUG
  130. // DEBUG: output byte code
  131. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc);
  132. #endif
  133. return 0;
  134. }
  135. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  136. {
  137. Reset(builder, script, outFunc);
  138. // Insert a JitEntry at the start of the function for JIT compilers
  139. byteCode.InstrPTR(asBC_JitEntry, 0);
  140. // Find the corresponding constructor
  141. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  142. int constructor = 0;
  143. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  144. {
  145. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  146. {
  147. constructor = dt.GetBehaviour()->constructors[n];
  148. break;
  149. }
  150. }
  151. // Allocate the class and instantiate it with the constructor
  152. int varOffset = AllocateVariable(dt, true);
  153. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  154. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  155. // Copy all arguments to the top of the stack
  156. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  157. int offset = (int)outFunc->GetSpaceNeededForArguments();
  158. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  159. {
  160. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  161. outFunc->parameterTypes[a].IsReference() )
  162. {
  163. offset -= AS_PTR_SIZE;
  164. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  165. }
  166. else
  167. {
  168. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  169. {
  170. offset -= 2;
  171. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  172. }
  173. else
  174. {
  175. offset -= 1;
  176. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  177. }
  178. }
  179. }
  180. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  181. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  182. // Return a handle to the newly created object
  183. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  184. byteCode.Ret(argDwords);
  185. FinalizeFunction();
  186. // Tell the virtual machine not to clean up parameters on exception
  187. outFunc->dontCleanUpOnException = true;
  188. /*
  189. #ifdef AS_DEBUG
  190. // DEBUG: output byte code
  191. asCString args;
  192. args.Format("%d", outFunc->parameterTypes.GetLength());
  193. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  194. #endif
  195. */
  196. return 0;
  197. }
  198. void asCCompiler::FinalizeFunction()
  199. {
  200. TimeIt("asCCompiler::FinalizeFunction");
  201. asASSERT( outFunc->scriptData );
  202. asUINT n;
  203. // Finalize the bytecode
  204. byteCode.Finalize(tempVariableOffsets);
  205. byteCode.ExtractObjectVariableInfo(outFunc);
  206. // Compile the list of object variables for the exception handler
  207. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  208. for( n = 0; n < variableAllocations.GetLength(); n++ )
  209. {
  210. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  211. {
  212. if( variableIsOnHeap[n] )
  213. {
  214. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  215. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  216. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  217. }
  218. }
  219. }
  220. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  221. for( n = 0; n < variableAllocations.GetLength(); n++ )
  222. {
  223. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  224. {
  225. if( !variableIsOnHeap[n] )
  226. {
  227. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  228. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  229. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  230. }
  231. }
  232. }
  233. // Copy byte code to the function
  234. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  235. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  236. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  237. outFunc->AddReferences();
  238. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  239. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  240. // Extract the script section indexes too if there are any entries that are different from the function's script section
  241. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  242. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  243. {
  244. if( byteCode.sectionIdxs[n] != lastIdx )
  245. {
  246. lastIdx = byteCode.sectionIdxs[n];
  247. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  248. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  249. }
  250. }
  251. }
  252. // internal
  253. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  254. {
  255. int stackPos = 0;
  256. if( outFunc->objectType )
  257. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  258. // Add the first variable scope, which the parameters and
  259. // variables declared in the outermost statement block is
  260. // part of.
  261. AddVariableScope();
  262. bool isDestructor = false;
  263. asCDataType returnType;
  264. // Examine return type
  265. returnType = outFunc->returnType;
  266. // Check if this is a constructor or destructor
  267. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  268. {
  269. if( outFunc->name[0] == '~' )
  270. isDestructor = true;
  271. else if( outFunc->objectType->name == outFunc->name )
  272. m_isConstructor = true;
  273. }
  274. // Is the return type allowed?
  275. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  276. !returnType.CanBeInstantiated() )
  277. {
  278. // TODO: Hasn't this been validated by the builder already?
  279. asCString str;
  280. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  281. Error(str, func);
  282. }
  283. // If the return type is a value type returned by value the address of the
  284. // location where the value will be stored is pushed on the stack before
  285. // the arguments
  286. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  287. stackPos -= AS_PTR_SIZE;
  288. asCVariableScope vs(0);
  289. // Declare parameters
  290. asUINT n;
  291. for( n = 0; n < parameterNames.GetLength(); n++ )
  292. {
  293. // Get the parameter type
  294. asCDataType &type = outFunc->parameterTypes[n];
  295. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  296. // Is the data type allowed?
  297. // TODO: Hasn't this been validated by the builder already?
  298. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  299. (!type.IsReference() && !type.CanBeInstantiated()) )
  300. {
  301. asCString parm = type.Format();
  302. if( inoutFlag == asTM_INREF )
  303. parm += "in";
  304. else if( inoutFlag == asTM_OUTREF )
  305. parm += "out";
  306. asCString str;
  307. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  308. Error(str, func);
  309. }
  310. // If the parameter has a name then declare it as variable
  311. if( parameterNames[n] != "" )
  312. {
  313. asCString &name = parameterNames[n];
  314. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  315. {
  316. // TODO: It might be an out-of-memory too
  317. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  318. }
  319. // Add marker for variable declaration
  320. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  321. outFunc->AddVariable(name, type, stackPos);
  322. }
  323. else
  324. vs.DeclareVariable("", type, stackPos, true);
  325. // Move to next parameter
  326. stackPos -= type.GetSizeOnStackDWords();
  327. }
  328. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  329. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  330. variables->DeclareVariable("return", returnType, stackPos, true);
  331. return stackPos;
  332. }
  333. void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
  334. {
  335. asASSERT( m_classDecl );
  336. // Initialize each member in the order they were declared
  337. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  338. {
  339. asCObjectProperty *prop = outFunc->objectType->properties[n];
  340. // Check if the property has an initialization expression
  341. asCScriptNode *declNode = 0;
  342. asCScriptNode *initNode = 0;
  343. asCScriptCode *initScript = 0;
  344. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  345. {
  346. if( m_classDecl->propInits[m].name == prop->name )
  347. {
  348. declNode = m_classDecl->propInits[m].declNode;
  349. initNode = m_classDecl->propInits[m].initNode;
  350. initScript = m_classDecl->propInits[m].file;
  351. break;
  352. }
  353. }
  354. // If declNode is null, the property was inherited in which case
  355. // it was already initialized by the base class' constructor
  356. if( declNode )
  357. {
  358. if( initNode )
  359. {
  360. if( onlyDefaults )
  361. continue;
  362. #ifdef AS_NO_MEMBER_INIT
  363. // Give an error as the initialization in the declaration has been disabled
  364. asCScriptCode *origScript = script;
  365. script = initScript;
  366. Error("Initialization of members in declaration is not supported", initNode);
  367. script = origScript;
  368. // Clear the initialization node
  369. initNode = 0;
  370. initScript = script;
  371. #else
  372. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  373. asCParser parser(builder);
  374. int r = parser.ParseVarInit(initScript, initNode);
  375. if( r < 0 )
  376. continue;
  377. initNode = parser.GetScriptNode();
  378. #endif
  379. }
  380. else
  381. {
  382. if( !onlyDefaults )
  383. continue;
  384. }
  385. #ifdef AS_NO_MEMBER_INIT
  386. // The initialization will be done in the asCScriptObject constructor, so
  387. // here we should just validate that the member has a default constructor
  388. if( prop->type.IsObject() &&
  389. !prop->type.IsObjectHandle() &&
  390. (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
  391. prop->type.GetBehaviour()->factory == 0) ||
  392. ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
  393. prop->type.GetBehaviour()->construct == 0 &&
  394. !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
  395. {
  396. // Class has no default factory/constructor.
  397. asCString str;
  398. // TODO: funcdef: asCDataType should have a GetTypeName()
  399. if( prop->type.GetFuncDef() )
  400. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  401. else
  402. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
  403. Error(str, declNode);
  404. }
  405. #else
  406. // Temporarily set the script that is being compiled to where the member initialization is declared.
  407. // The script can be different when including mixin classes from a different script section
  408. asCScriptCode *origScript = script;
  409. script = initScript;
  410. // Add a line instruction with the position of the declaration
  411. LineInstr(byteCode, declNode->tokenPos);
  412. // Compile the initialization
  413. asQWORD constantValue;
  414. asCByteCode bc(engine);
  415. CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  416. bc.OptimizeLocally(tempVariableOffsets);
  417. byteCode->AddCode(&bc);
  418. script = origScript;
  419. #endif
  420. }
  421. }
  422. }
  423. // Entry
  424. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> &parameterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  425. {
  426. TimeIt("asCCompiler::CompileFunction");
  427. Reset(builder, script, outFunc);
  428. int buildErrors = builder->numErrors;
  429. int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
  430. //--------------------------------------------
  431. // Compile the statement block
  432. if( m_isConstructor )
  433. m_classDecl = classDecl;
  434. // We need to parse the statement block now
  435. asCScriptNode *blockBegin;
  436. // If the function signature was implicit, e.g. virtual property
  437. // accessor, then the received node already is the statement block
  438. if( func->nodeType != snStatementBlock )
  439. blockBegin = func->lastChild;
  440. else
  441. blockBegin = func;
  442. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  443. // 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
  444. asCParser parser(builder);
  445. int r = parser.ParseStatementBlock(script, blockBegin);
  446. if( r < 0 ) return -1;
  447. asCScriptNode *block = parser.GetScriptNode();
  448. // Reserve a label for the cleanup code
  449. nextLabel++;
  450. bool hasReturn;
  451. asCByteCode bc(engine);
  452. LineInstr(&bc, blockBegin->tokenPos);
  453. CompileStatementBlock(block, false, &hasReturn, &bc);
  454. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  455. // Make sure there is a return in all paths (if not return type is void)
  456. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  457. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  458. {
  459. if( hasReturn == false )
  460. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  461. }
  462. //------------------------------------------------
  463. // Concatenate the bytecode
  464. // Insert a JitEntry at the start of the function for JIT compilers
  465. byteCode.InstrPTR(asBC_JitEntry, 0);
  466. if( outFunc->objectType )
  467. {
  468. if( m_isConstructor )
  469. {
  470. if( outFunc->objectType->derivedFrom )
  471. {
  472. // Call the base class' default constructor unless called manually in the code
  473. if( !m_isConstructorCalled )
  474. {
  475. if( outFunc->objectType->derivedFrom->beh.construct )
  476. {
  477. // Initialize members without explicit expression first
  478. CompileMemberInitialization(&byteCode, true);
  479. // Call base class' constructor
  480. asCByteCode tmpBC(engine);
  481. tmpBC.InstrSHORT(asBC_PSF, 0);
  482. tmpBC.Instr(asBC_RDSPtr);
  483. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  484. tmpBC.OptimizeLocally(tempVariableOffsets);
  485. byteCode.AddCode(&tmpBC);
  486. // Add the initialization of the members with explicit expressions
  487. CompileMemberInitialization(&byteCode, false);
  488. }
  489. else
  490. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  491. }
  492. else
  493. {
  494. // Only initialize members that don't have an explicit expression
  495. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  496. CompileMemberInitialization(&byteCode, true);
  497. }
  498. }
  499. else
  500. {
  501. // Add the initialization of the members
  502. CompileMemberInitialization(&byteCode, true);
  503. CompileMemberInitialization(&byteCode, false);
  504. }
  505. }
  506. }
  507. // Add the code for the statement block
  508. byteCode.AddCode(&bc);
  509. // Count total variable size
  510. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  511. outFunc->scriptData->variableSpace = varSize;
  512. // Deallocate all local variables
  513. int n;
  514. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  515. {
  516. sVariable *v = variables->variables[n];
  517. if( v->stackOffset > 0 )
  518. {
  519. // Call variables destructors
  520. if( v->name != "return" && v->name != "return address" )
  521. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  522. DeallocateVariable(v->stackOffset);
  523. }
  524. }
  525. // This is the label that return statements jump to
  526. // in order to exit the function
  527. byteCode.Label(0);
  528. // Call destructors for function parameters
  529. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  530. {
  531. sVariable *v = variables->variables[n];
  532. if( v->stackOffset <= 0 )
  533. {
  534. // Call variable destructors here, for variables not yet destroyed
  535. if( v->name != "return" && v->name != "return address" )
  536. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  537. }
  538. // Do not deallocate parameters
  539. }
  540. // Check if the number of labels in the functions isn't too many to be handled
  541. if( nextLabel >= (1<<15) )
  542. Error(TXT_TOO_MANY_JUMP_LABELS, func);
  543. // If there are compile errors, there is no reason to build the final code
  544. if( hasCompileErrors || builder->numErrors != buildErrors )
  545. return -1;
  546. // At this point there should be no variables allocated
  547. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  548. // Remove the variable scope
  549. RemoveVariableScope();
  550. byteCode.Ret(-stackPos);
  551. FinalizeFunction();
  552. #ifdef AS_DEBUG
  553. // DEBUG: output byte code
  554. if( outFunc->objectType )
  555. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  556. else
  557. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  558. #endif
  559. return 0;
  560. }
  561. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  562. {
  563. if( !type.IsObject() )
  564. return 0;
  565. // CallCopyConstructor should not be called for object handles.
  566. asASSERT( !type.IsObjectHandle() );
  567. asCArray<asSExprContext*> args;
  568. args.PushLast(arg);
  569. // The reference parameter must be pushed on the stack
  570. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  571. // Since we're calling the copy constructor, we have to trust the function to not do
  572. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  573. // copies of the argument in order to guarantee safety.
  574. if( type.GetObjectType()->flags & asOBJ_REF )
  575. {
  576. asSExprContext ctx(engine);
  577. int func = 0;
  578. asSTypeBehaviour *beh = type.GetBehaviour();
  579. if( beh ) func = beh->copyfactory;
  580. if( func > 0 )
  581. {
  582. if( !isGlobalVar )
  583. {
  584. // Call factory and store the handle in the given variable
  585. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  586. // Pop the reference left by the function call
  587. ctx.bc.Instr(asBC_PopPtr);
  588. }
  589. else
  590. {
  591. // Call factory
  592. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  593. // Store the returned handle in the global variable
  594. ctx.bc.Instr(asBC_RDSPtr);
  595. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  596. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  597. ctx.bc.Instr(asBC_PopPtr);
  598. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  599. }
  600. bc->AddCode(&ctx.bc);
  601. return 0;
  602. }
  603. }
  604. else
  605. {
  606. asSTypeBehaviour *beh = type.GetBehaviour();
  607. int func = beh ? beh->copyconstruct : 0;
  608. if( func > 0 )
  609. {
  610. // Push the address where the object will be stored on the stack, before the argument
  611. // TODO: When the context is serializable this probably has to be changed, since this
  612. // pointer can remain on the stack while the context is suspended. There is no
  613. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  614. asCByteCode tmp(engine);
  615. if( isGlobalVar )
  616. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  617. else if( isObjectOnHeap )
  618. tmp.InstrSHORT(asBC_PSF, (short)offset);
  619. tmp.AddCode(bc);
  620. bc->AddCode(&tmp);
  621. // When the object is allocated on the stack the object pointer
  622. // must be pushed on the stack after the arguments
  623. if( !isObjectOnHeap )
  624. {
  625. asASSERT( !isGlobalVar );
  626. bc->InstrSHORT(asBC_PSF, (short)offset);
  627. if( derefDest )
  628. {
  629. // The variable is a reference to the real location, so we need to dereference it
  630. bc->Instr(asBC_RDSPtr);
  631. }
  632. }
  633. asSExprContext ctx(engine);
  634. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  635. bc->AddCode(&ctx.bc);
  636. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  637. // Mark the object as initialized
  638. if( !isObjectOnHeap )
  639. bc->ObjInfo(offset, asOBJ_INIT);
  640. return 0;
  641. }
  642. }
  643. // Class has no copy constructor/factory.
  644. asCString str;
  645. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  646. Error(str, node);
  647. return -1;
  648. }
  649. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  650. {
  651. if( !type.IsObject() || type.IsObjectHandle() )
  652. return 0;
  653. if( type.GetObjectType()->flags & asOBJ_REF )
  654. {
  655. asSExprContext ctx(engine);
  656. ctx.exprNode = node;
  657. int func = 0;
  658. asSTypeBehaviour *beh = type.GetBehaviour();
  659. if( beh )
  660. {
  661. func = beh->factory;
  662. // If no trivial default factory is found, look for a factory where all params have default args
  663. if( func == 0 )
  664. {
  665. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  666. {
  667. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  668. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  669. f->defaultArgs[0] != 0 )
  670. {
  671. func = beh->factories[n];
  672. break;
  673. }
  674. }
  675. }
  676. }
  677. if( func > 0 )
  678. {
  679. asCArray<asSExprContext *> args;
  680. asCScriptFunction *f = engine->scriptFunctions[func];
  681. if( f->parameterTypes.GetLength() )
  682. {
  683. // Add the default values for arguments not explicitly supplied
  684. CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
  685. PrepareFunctionCall(func, &ctx.bc, args);
  686. MoveArgsToStack(func, &ctx.bc, args, false);
  687. }
  688. if( isVarGlobOrMem == 0 )
  689. {
  690. // Call factory and store the handle in the given variable
  691. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  692. // Pop the reference left by the function call
  693. ctx.bc.Instr(asBC_PopPtr);
  694. }
  695. else
  696. {
  697. // Call factory
  698. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  699. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  700. // instead of first storing it in a local variable and then copying it to the
  701. // destination.
  702. if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
  703. {
  704. // Only dereference the variable if not a scoped type
  705. ctx.bc.Instr(asBC_RDSPtr);
  706. }
  707. if( isVarGlobOrMem == 1 )
  708. {
  709. // Store the returned handle in the global variable
  710. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  711. }
  712. else
  713. {
  714. // Store the returned handle in the class member
  715. ctx.bc.InstrSHORT(asBC_PSF, 0);
  716. ctx.bc.Instr(asBC_RDSPtr);
  717. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  718. }
  719. if( type.GetObjectType()->flags & asOBJ_SCOPED )
  720. {
  721. // For scoped typed we must move the reference from the local
  722. // variable rather than copy it as there is no AddRef behaviour
  723. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  724. // Clear the local variable so the reference isn't released
  725. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  726. }
  727. else
  728. {
  729. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  730. }
  731. ctx.bc.Instr(asBC_PopPtr);
  732. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  733. }
  734. bc->AddCode(&ctx.bc);
  735. // Cleanup
  736. for( asUINT n = 0; n < args.GetLength(); n++ )
  737. if( args[n] )
  738. {
  739. asDELETE(args[n],asSExprContext);
  740. }
  741. return 0;
  742. }
  743. }
  744. else
  745. {
  746. asSExprContext ctx(engine);
  747. ctx.exprNode = node;
  748. asSTypeBehaviour *beh = type.GetBehaviour();
  749. int func = 0;
  750. if( beh )
  751. {
  752. func = beh->construct;
  753. // If no trivial default constructor is found, look for a constructor where all params have default args
  754. if( func == 0 )
  755. {
  756. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  757. {
  758. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  759. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  760. f->defaultArgs[0] != 0 )
  761. {
  762. func = beh->constructors[n];
  763. break;
  764. }
  765. }
  766. }
  767. }
  768. // Allocate and initialize with the default constructor
  769. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  770. {
  771. asCArray<asSExprContext *> args;
  772. asCScriptFunction *f = engine->scriptFunctions[func];
  773. if( f && f->parameterTypes.GetLength() )
  774. {
  775. // Add the default values for arguments not explicitly supplied
  776. CompileDefaultAndNamedArgs(node, args, func, type.GetObjectType());
  777. PrepareFunctionCall(func, &ctx.bc, args);
  778. MoveArgsToStack(func, &ctx.bc, args, false);
  779. }
  780. if( !isObjectOnHeap )
  781. {
  782. if( isVarGlobOrMem == 0 )
  783. {
  784. // There is nothing to do if there is no function,
  785. // as the memory is already allocated on the stack
  786. if( func )
  787. {
  788. // Call the constructor as a normal function
  789. bc->InstrSHORT(asBC_PSF, (short)offset);
  790. if( derefDest )
  791. bc->Instr(asBC_RDSPtr);
  792. asSExprContext ctx(engine);
  793. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  794. bc->AddCode(&ctx.bc);
  795. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  796. // Mark the object as initialized
  797. bc->ObjInfo(offset, asOBJ_INIT);
  798. }
  799. }
  800. else if( isVarGlobOrMem == 2 )
  801. {
  802. // Only POD types can be allocated inline in script classes
  803. asASSERT( type.GetObjectType()->flags & asOBJ_POD );
  804. if( func )
  805. {
  806. // Call the constructor as a normal function
  807. bc->InstrSHORT(asBC_PSF, 0);
  808. bc->Instr(asBC_RDSPtr);
  809. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  810. asSExprContext ctx(engine);
  811. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  812. bc->AddCode(&ctx.bc);
  813. }
  814. }
  815. else
  816. {
  817. asASSERT( false );
  818. }
  819. }
  820. else
  821. {
  822. if( isVarGlobOrMem == 0 )
  823. bc->InstrSHORT(asBC_PSF, (short)offset);
  824. else if( isVarGlobOrMem == 1 )
  825. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  826. else
  827. {
  828. bc->InstrSHORT(asBC_PSF, 0);
  829. bc->Instr(asBC_RDSPtr);
  830. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  831. }
  832. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  833. }
  834. // Cleanup
  835. for( asUINT n = 0; n < args.GetLength(); n++ )
  836. if( args[n] )
  837. {
  838. asDELETE(args[n],asSExprContext);
  839. }
  840. return 0;
  841. }
  842. }
  843. // Class has no default factory/constructor.
  844. asCString str;
  845. // TODO: funcdef: asCDataType should have a GetTypeName()
  846. if( type.GetFuncDef() )
  847. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  848. else
  849. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  850. Error(str, node);
  851. return -1;
  852. }
  853. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  854. {
  855. if( !type.IsReference() )
  856. {
  857. // Call destructor for the data type
  858. if( type.IsObject() )
  859. {
  860. // The null pointer doesn't need to be destroyed
  861. if( type.IsNullHandle() )
  862. return;
  863. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  864. if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN )
  865. return;
  866. if( isObjectOnHeap || type.IsObjectHandle() )
  867. {
  868. // Free the memory
  869. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  870. }
  871. else
  872. {
  873. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  874. if( type.GetBehaviour()->destruct )
  875. {
  876. // Call the destructor as a regular function
  877. asSExprContext ctx(engine);
  878. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  879. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  880. ctx.bc.OptimizeLocally(tempVariableOffsets);
  881. bc->AddCode(&ctx.bc);
  882. }
  883. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  884. // Mark the object as destroyed
  885. bc->ObjInfo(offset, asOBJ_UNINIT);
  886. }
  887. }
  888. }
  889. }
  890. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  891. {
  892. int r, c;
  893. script->ConvertPosToRowCol(pos, &r, &c);
  894. bc->Line(r, c, script->idx);
  895. }
  896. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  897. {
  898. *hasReturn = false;
  899. bool isFinished = false;
  900. bool hasUnreachableCode = false;
  901. bool hasReturnBefore = false;
  902. if( ownVariableScope )
  903. {
  904. bc->Block(true);
  905. AddVariableScope();
  906. }
  907. asCScriptNode *node = block->firstChild;
  908. while( node )
  909. {
  910. #ifdef AS_DEBUG
  911. // Keep the current line in a variable so it will be easier
  912. // to determine where in a script an assert is occurring.
  913. int currentLine = 0;
  914. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  915. #endif
  916. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  917. {
  918. // Empty statements don't count
  919. if( node->nodeType != snExpressionStatement || node->firstChild )
  920. {
  921. hasUnreachableCode = true;
  922. Warning(TXT_UNREACHABLE_CODE, node);
  923. }
  924. if( *hasReturn )
  925. hasReturnBefore = true;
  926. }
  927. if( node->nodeType == snBreak || node->nodeType == snContinue )
  928. isFinished = true;
  929. asCByteCode statement(engine);
  930. if( node->nodeType == snDeclaration )
  931. CompileDeclaration(node, &statement);
  932. else
  933. CompileStatement(node, hasReturn, &statement);
  934. // Ignore missing returns in unreachable code paths
  935. if( !(*hasReturn) && hasReturnBefore )
  936. *hasReturn = true;
  937. LineInstr(bc, node->tokenPos);
  938. bc->AddCode(&statement);
  939. if( !hasCompileErrors )
  940. {
  941. asASSERT( tempVariables.GetLength() == 0 );
  942. asASSERT( reservedVariables.GetLength() == 0 );
  943. }
  944. node = node->next;
  945. }
  946. if( ownVariableScope )
  947. {
  948. // Deallocate variables in this block, in reverse order
  949. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  950. {
  951. sVariable *v = variables->variables[n];
  952. // Call variable destructors here, for variables not yet destroyed
  953. // If the block is terminated with a break, continue, or
  954. // return the variables are already destroyed
  955. if( !isFinished && !*hasReturn )
  956. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  957. // Don't deallocate function parameters
  958. if( v->stackOffset > 0 )
  959. DeallocateVariable(v->stackOffset);
  960. }
  961. RemoveVariableScope();
  962. bc->Block(false);
  963. }
  964. }
  965. // Entry
  966. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  967. {
  968. Reset(builder, script, outFunc);
  969. // Add a variable scope (even though variables can't be declared)
  970. AddVariableScope();
  971. gvar->isPureConstant = false;
  972. // Parse the initialization nodes
  973. asCParser parser(builder);
  974. if( node )
  975. {
  976. int r = parser.ParseVarInit(script, node);
  977. if( r < 0 )
  978. return r;
  979. node = parser.GetScriptNode();
  980. }
  981. asSExprContext compiledCtx(engine);
  982. bool preCompiled = false;
  983. if( gvar->datatype.IsAuto() )
  984. preCompiled = CompileAutoType(gvar->datatype, compiledCtx, node, gvar->declaredAtNode);
  985. if( gvar->property == 0 )
  986. {
  987. gvar->property = builder->module->AllocateGlobalProperty(gvar->name.AddressOf(), gvar->datatype, gvar->ns);
  988. gvar->index = gvar->property->id;
  989. }
  990. // Compile the expression
  991. asSExprContext ctx(engine);
  992. asQWORD constantValue = 0;
  993. if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  994. {
  995. // Should the variable be marked as pure constant?
  996. if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
  997. {
  998. gvar->isPureConstant = true;
  999. gvar->constantValue = constantValue;
  1000. }
  1001. }
  1002. // Concatenate the bytecode
  1003. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1004. // Add information on the line number for the global variable
  1005. size_t pos = 0;
  1006. if( gvar->declaredAtNode )
  1007. pos = gvar->declaredAtNode->tokenPos;
  1008. else if( gvar->initializationNode )
  1009. pos = gvar->initializationNode->tokenPos;
  1010. LineInstr(&byteCode, pos);
  1011. // Reserve space for all local variables
  1012. outFunc->scriptData->variableSpace = varSize;
  1013. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1014. byteCode.AddCode(&ctx.bc);
  1015. // Deallocate variables in this block, in reverse order
  1016. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1017. {
  1018. sVariable *v = variables->variables[n];
  1019. // Call variable destructors here, for variables not yet destroyed
  1020. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1021. DeallocateVariable(v->stackOffset);
  1022. }
  1023. if( hasCompileErrors ) return -1;
  1024. // At this point there should be no variables allocated
  1025. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1026. // Remove the variable scope again
  1027. RemoveVariableScope();
  1028. byteCode.Ret(0);
  1029. FinalizeFunction();
  1030. #ifdef AS_DEBUG
  1031. // DEBUG: output byte code
  1032. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  1033. #endif
  1034. return 0;
  1035. }
  1036. void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
  1037. {
  1038. // Don't do anything if this is not a deferred global function
  1039. if( !ctx->IsGlobalFunc() )
  1040. return;
  1041. // Determine the namespace
  1042. asSNameSpace *ns = 0;
  1043. asCString name = "";
  1044. int pos = ctx->methodName.FindLast("::");
  1045. if( pos >= 0 )
  1046. {
  1047. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1048. // Cut off the ::
  1049. if( nsName.GetLength() > 2 )
  1050. nsName.SetLength(nsName.GetLength()-2);
  1051. ns = DetermineNameSpace(nsName);
  1052. name = ctx->methodName.SubString(pos+2);
  1053. }
  1054. else
  1055. {
  1056. DetermineNameSpace("");
  1057. name = ctx->methodName;
  1058. }
  1059. asCArray<int> funcs;
  1060. if( ns )
  1061. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1062. // CompileVariableAccess should guarantee that at least one function is exists
  1063. asASSERT( funcs.GetLength() > 0 );
  1064. if( funcs.GetLength() > 1 )
  1065. {
  1066. asCString str;
  1067. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1068. Error(str, node);
  1069. // Fall through so the compiler can continue as if only one function was matching
  1070. }
  1071. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1072. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1073. outFunc->IsShared() )
  1074. {
  1075. asCString msg;
  1076. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1077. Error(msg, node);
  1078. // Fall through so the compiler can continue anyway
  1079. }
  1080. // Push the function pointer on the stack
  1081. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1082. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  1083. ctx->type.dataType.MakeHandle(true);
  1084. ctx->type.isExplicitHandle = true;
  1085. ctx->methodName = "";
  1086. }
  1087. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool derefDestination)
  1088. {
  1089. asASSERT( dt.GetObjectType() );
  1090. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1091. // Use copy constructor if available.
  1092. if( dt.GetObjectType()->beh.copyconstruct )
  1093. {
  1094. PrepareForAssignment(&dt, arg, node, true);
  1095. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1096. if( r < 0 && tempVariables.Exists(offset) )
  1097. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1098. }
  1099. else
  1100. {
  1101. // TODO: 2.28.1: Need to reserve variables, as the default constructor may need
  1102. // to allocate temporary variables to compute default args
  1103. // Allocate and construct the temporary object before whatever is already in the bytecode
  1104. asCByteCode tmpBC(engine);
  1105. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1106. if( r < 0 )
  1107. {
  1108. if( tempVariables.Exists(offset) )
  1109. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1110. return;
  1111. }
  1112. tmpBC.AddCode(bc);
  1113. bc->AddCode(&tmpBC);
  1114. // Assign the evaluated expression to the temporary variable
  1115. PrepareForAssignment(&dt, arg, node, true);
  1116. bc->AddCode(&arg->bc);
  1117. // Call the opAssign method to assign the value to the temporary object
  1118. dt.MakeReference(isObjectOnHeap);
  1119. asCTypeInfo type;
  1120. type.Set(dt);
  1121. type.isTemporary = true;
  1122. type.stackOffset = (short)offset;
  1123. if( dt.IsObjectHandle() )
  1124. type.isExplicitHandle = true;
  1125. bc->InstrSHORT(asBC_PSF, (short)offset);
  1126. if( derefDestination )
  1127. bc->Instr(asBC_RDSPtr);
  1128. r = PerformAssignment(&type, &arg->type, bc, node);
  1129. if( r < 0 )
  1130. {
  1131. if( tempVariables.Exists(offset) )
  1132. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1133. return;
  1134. }
  1135. // Pop the reference that was pushed on the stack if the result is an object
  1136. if( type.dataType.IsObject() )
  1137. bc->Instr(asBC_PopPtr);
  1138. // If the assignment operator returned an object by value it will
  1139. // be in a temporary variable which we need to destroy now
  1140. if( type.isTemporary && type.stackOffset != (short)offset )
  1141. ReleaseTemporaryVariable(type.stackOffset, bc);
  1142. // Release the original value too in case it is a temporary
  1143. ReleaseTemporaryVariable(arg->type, bc);
  1144. }
  1145. }
  1146. int asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1147. {
  1148. asCDataType param = *paramType;
  1149. if( paramType->GetTokenType() == ttQuestion )
  1150. {
  1151. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1152. DetermineSingleFunc(ctx, node);
  1153. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1154. param = ctx->type.dataType;
  1155. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1156. // Treat the void expression like a null handle when working with var types
  1157. if( ctx->type.IsVoidExpression() )
  1158. param = asCDataType::CreateNullHandle();
  1159. // If value assign is disabled for reference types, then make
  1160. // sure to always pass the handle to ? parameters
  1161. if( builder->engine->ep.disallowValueAssignForRefType &&
  1162. ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1163. {
  1164. param.MakeHandle(true);
  1165. }
  1166. param.MakeReference(paramType->IsReference());
  1167. param.MakeReadOnly(paramType->IsReadOnly());
  1168. }
  1169. else
  1170. param = *paramType;
  1171. asCDataType dt = param;
  1172. // Need to protect arguments by reference
  1173. if( isFunction && dt.IsReference() )
  1174. {
  1175. // Allocate a temporary variable of the same type as the argument
  1176. dt.MakeReference(false);
  1177. dt.MakeReadOnly(false);
  1178. int offset;
  1179. if( refType == 1 ) // &in
  1180. {
  1181. ProcessPropertyGetAccessor(ctx, node);
  1182. // Add the type id as hidden arg if the parameter is a ? type
  1183. if( paramType->GetTokenType() == ttQuestion )
  1184. {
  1185. asCByteCode tmpBC(engine);
  1186. // Place the type id on the stack as a hidden parameter
  1187. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1188. // Insert the code before the expression code
  1189. tmpBC.AddCode(&ctx->bc);
  1190. ctx->bc.AddCode(&tmpBC);
  1191. }
  1192. if( dt.IsPrimitive() )
  1193. {
  1194. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1195. // Even if the same variable is passed in another argument as non-const then there is no problem
  1196. IsVariableInitialized(&ctx->type, node);
  1197. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1198. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1199. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1200. ConvertToTempVariable(ctx);
  1201. PushVariableOnStack(ctx, true);
  1202. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1203. }
  1204. else if( ctx->type.dataType.IsNullHandle() )
  1205. {
  1206. // Need to initialize a local temporary variable to
  1207. // represent the null handle when passed as reference
  1208. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1209. ctx->bc.Instr(asBC_PopPtr);
  1210. dt.MakeHandle(true);
  1211. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1212. // Push the reference to the variable on the stack
  1213. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1214. ctx->type.SetVariable(dt, offset, true);
  1215. }
  1216. else
  1217. {
  1218. IsVariableInitialized(&ctx->type, node);
  1219. if( !isMakingCopy )
  1220. {
  1221. // Even though the parameter expects a reference, it is only meant to be
  1222. // used as input value and doesn't have to refer to the actual object, so it
  1223. // is OK to do an implicit conversion.
  1224. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1225. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1226. {
  1227. asCString str;
  1228. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  1229. Error(str, node);
  1230. ctx->type.Set(param);
  1231. return -1;
  1232. }
  1233. // The compiler must guarantee that the object stays alive during the execution
  1234. // of the function, and it must also guarantee that the value isn't modified by
  1235. // the function.
  1236. // If the argument is a temporary local variable then it is safe to be passed to
  1237. // the function as it is, since the local variable will stay alive, and since it
  1238. // is temporary there is no side effect if the function modifies it.
  1239. // If the parameter is read-only and therefor guaranteed not to be modified by the
  1240. // function, then it is enough that the variable is local to guarantee the lifetime.
  1241. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  1242. {
  1243. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && param.IsReadOnly() )
  1244. {
  1245. // If the object is a reference type, and the parameter is a const reference,
  1246. // then it is not necessary to make a copy of the object. The compiler just needs
  1247. // to hold a handle to guarantee the lifetime.
  1248. // Allocate a handle variable
  1249. dt.MakeHandle(true);
  1250. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1251. // Copy the handle
  1252. Dereference(ctx, true);
  1253. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1254. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1255. ctx->bc.Instr(asBC_PopPtr);
  1256. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1257. // The type should be set to the param type instead of dt to guarantee
  1258. // that the expression keeps the correct type for variable ? args. Otherwise
  1259. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1260. ctx->type.SetVariable(param, offset, true);
  1261. }
  1262. else
  1263. {
  1264. // Allocate and initialize a temporary local object
  1265. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1266. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1267. // Push the object pointer on the stack
  1268. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1269. if( dt.IsObject() && !dt.IsObjectHandle() )
  1270. ctx->bc.Instr(asBC_RDSPtr);
  1271. // Set the resulting type
  1272. ctx->type.Set(dt);
  1273. ctx->type.isTemporary = true;
  1274. ctx->type.stackOffset = short(offset);
  1275. if( dt.IsObjectHandle() )
  1276. ctx->type.isExplicitHandle = true;
  1277. ctx->type.dataType.MakeReference(false);
  1278. if( paramType->IsReadOnly() )
  1279. ctx->type.dataType.MakeReadOnly(true);
  1280. }
  1281. }
  1282. }
  1283. else
  1284. {
  1285. // We must guarantee that the address to the value is on the stack
  1286. if( ctx->type.dataType.IsObject() &&
  1287. !ctx->type.dataType.IsObjectHandle() &&
  1288. ctx->type.dataType.IsReference() )
  1289. Dereference(ctx, true);
  1290. }
  1291. }
  1292. }
  1293. else if( refType == 2 ) // &out
  1294. {
  1295. // Add the type id as hidden arg if the parameter is a ? type
  1296. if( paramType->GetTokenType() == ttQuestion )
  1297. {
  1298. asCByteCode tmpBC(engine);
  1299. // Place the type id on the stack as a hidden parameter
  1300. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1301. // Insert the code before the expression code
  1302. tmpBC.AddCode(&ctx->bc);
  1303. ctx->bc.AddCode(&tmpBC);
  1304. }
  1305. // Make sure the variable is not used in the expression
  1306. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1307. if( dt.IsPrimitive() )
  1308. {
  1309. ctx->type.SetVariable(dt, offset, true);
  1310. PushVariableOnStack(ctx, true);
  1311. }
  1312. else
  1313. {
  1314. // TODO: 2.28.1: Need to reserve variables, as the default constructor may need
  1315. // to allocate temporary variables to compute default args
  1316. // Allocate and construct the temporary object
  1317. asCByteCode tmpBC(engine);
  1318. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1319. // Insert the code before the expression code
  1320. tmpBC.AddCode(&ctx->bc);
  1321. ctx->bc.AddCode(&tmpBC);
  1322. dt.MakeReference(!dt.IsObject() || dt.IsObjectHandle());
  1323. asCTypeInfo type;
  1324. type.Set(dt);
  1325. type.isTemporary = true;
  1326. type.stackOffset = (short)offset;
  1327. ctx->type = type;
  1328. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1329. if( dt.IsObject() && !dt.IsObjectHandle() )
  1330. ctx->bc.Instr(asBC_RDSPtr);
  1331. }
  1332. // After the function returns the temporary variable will
  1333. // be assigned to the expression, if it is a valid lvalue
  1334. }
  1335. else if( refType == asTM_INOUTREF )
  1336. {
  1337. ProcessPropertyGetAccessor(ctx, node);
  1338. // Add the type id as hidden arg if the parameter is a ? type
  1339. if( paramType->GetTokenType() == ttQuestion )
  1340. {
  1341. asCByteCode tmpBC(engine);
  1342. // Place the type id on the stack as a hidden parameter
  1343. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1344. // Insert the code before the expression code
  1345. tmpBC.AddCode(&ctx->bc);
  1346. ctx->bc.AddCode(&tmpBC);
  1347. }
  1348. // Literal constants cannot be passed to inout ref arguments
  1349. if( !ctx->type.isVariable && ctx->type.isConstant )
  1350. {
  1351. // Unless unsafe references are turned on and the reference is const
  1352. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1353. {
  1354. // Since the parameter is a const & make a copy.
  1355. ConvertToTempVariable(ctx);
  1356. ctx->type.dataType.MakeReadOnly(true);
  1357. }
  1358. else
  1359. {
  1360. Error(TXT_NOT_VALID_REFERENCE, node);
  1361. return -1;
  1362. }
  1363. }
  1364. // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
  1365. if( ctx->type.dataType.IsObject() && ctx->type.dataType.GetObjectType() != dt.GetObjectType() )
  1366. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1367. // Only objects that support object handles
  1368. // can be guaranteed to be safe. Local variables are
  1369. // already safe, so there is no need to add an extra
  1370. // references
  1371. if( !engine->ep.allowUnsafeReferences &&
  1372. !ctx->type.isVariable &&
  1373. ctx->type.dataType.IsObject() &&
  1374. !ctx->type.dataType.IsObjectHandle() &&
  1375. ((ctx->type.dataType.GetBehaviour()->addref &&
  1376. ctx->type.dataType.GetBehaviour()->release) ||
  1377. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1378. {
  1379. // Store a handle to the object as local variable
  1380. asSExprContext tmp(engine);
  1381. asCDataType dt = ctx->type.dataType;
  1382. dt.MakeHandle(true);
  1383. dt.MakeReference(false);
  1384. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1385. // Copy the handle
  1386. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1387. ctx->bc.Instr(asBC_RDSPtr);
  1388. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1389. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1390. ctx->bc.Instr(asBC_PopPtr);
  1391. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1392. dt.MakeHandle(false);
  1393. dt.MakeReference(true);
  1394. // Release previous temporary variable stored in the context (if any)
  1395. if( ctx->type.isTemporary )
  1396. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1397. ctx->type.SetVariable(dt, offset, true);
  1398. }
  1399. // Make sure the reference to the value is on the stack
  1400. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1401. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1402. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1403. Dereference(ctx, true);
  1404. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1405. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1406. else if( ctx->type.dataType.IsPrimitive() )
  1407. ctx->bc.Instr(asBC_PshRPtr);
  1408. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1409. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1410. }
  1411. }
  1412. else
  1413. {
  1414. ProcessPropertyGetAccessor(ctx, node);
  1415. if( dt.IsPrimitive() )
  1416. {
  1417. IsVariableInitialized(&ctx->type, node);
  1418. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1419. // Implicitly convert primitives to the parameter type
  1420. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1421. if( ctx->type.isVariable )
  1422. {
  1423. PushVariableOnStack(ctx, dt.IsReference());
  1424. }
  1425. else if( ctx->type.isConstant )
  1426. {
  1427. ConvertToVariable(ctx);
  1428. PushVariableOnStack(ctx, dt.IsReference());
  1429. }
  1430. }
  1431. else
  1432. {
  1433. IsVariableInitialized(&ctx->type, node);
  1434. // Implicitly convert primitives to the parameter type
  1435. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1436. // Was the conversion successful?
  1437. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1438. {
  1439. asCString str;
  1440. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1441. Error(str, node);
  1442. ctx->type.Set(dt);
  1443. return -1;
  1444. }
  1445. if( dt.IsObjectHandle() )
  1446. ctx->type.isExplicitHandle = true;
  1447. if( dt.IsObject() && !dt.IsNullHandle() )
  1448. {
  1449. if( !dt.IsReference() )
  1450. {
  1451. // Objects passed by value must be placed in temporary variables
  1452. // so that they are guaranteed to not be referenced anywhere else.
  1453. // The object must also be allocated on the heap, as the memory will
  1454. // be deleted by in as_callfunc_xxx.
  1455. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1456. // Local variables doesn't need to be copied into
  1457. // a temp if we're already compiling an assignment
  1458. if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
  1459. PrepareTemporaryObject(node, ctx, true);
  1460. // The implicit conversion shouldn't convert the object to
  1461. // non-reference yet. It will be dereferenced just before the call.
  1462. // Otherwise the object might be missed by the exception handler.
  1463. dt.MakeReference(true);
  1464. }
  1465. else
  1466. {
  1467. // An object passed by reference should place the pointer to
  1468. // the object on the stack.
  1469. dt.MakeReference(false);
  1470. }
  1471. }
  1472. }
  1473. }
  1474. // Don't put any pointer on the stack yet
  1475. if( param.IsReference() || (param.IsObject() && !param.IsNullHandle()) )
  1476. {
  1477. // &inout parameter may leave the reference on the stack already
  1478. if( refType != 3 )
  1479. {
  1480. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1481. if( ctx->type.isVariable || ctx->type.isTemporary )
  1482. {
  1483. ctx->bc.Instr(asBC_PopPtr);
  1484. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1485. ProcessDeferredParams(ctx);
  1486. }
  1487. }
  1488. }
  1489. return 0;
  1490. }
  1491. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1492. {
  1493. // When a match has been found, compile the final byte code using correct parameter types
  1494. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1495. // If the function being called is the opAssign or copy constructor for the same type
  1496. // as the argument, then we should avoid making temporary copy of the argument
  1497. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1498. bool makingCopy = false;
  1499. if( descr->parameterTypes.GetLength() == 1 &&
  1500. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1501. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1502. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1503. makingCopy = true;
  1504. // Add code for arguments
  1505. asSExprContext e(engine);
  1506. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1507. {
  1508. // Make sure PrepareArgument doesn't use any variable that is already
  1509. // being used by any of the following argument expressions
  1510. int l = int(reservedVariables.GetLength());
  1511. for( int m = n-1; m >= 0; m-- )
  1512. args[m]->bc.GetVarsUsed(reservedVariables);
  1513. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1514. reservedVariables.SetLength(l);
  1515. }
  1516. bc->AddCode(&e.bc);
  1517. }
  1518. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1519. {
  1520. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1521. int offset = 0;
  1522. if( addOneToOffset )
  1523. offset += AS_PTR_SIZE;
  1524. // The address of where the return value should be stored is push on top of the arguments
  1525. if( descr->DoesReturnOnStack() )
  1526. offset += AS_PTR_SIZE;
  1527. #ifdef AS_DEBUG
  1528. // If the function being called is the opAssign or copy constructor for the same type
  1529. // as the argument, then we should avoid making temporary copy of the argument
  1530. bool makingCopy = false;
  1531. if( descr->parameterTypes.GetLength() == 1 &&
  1532. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1533. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1534. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1535. makingCopy = true;
  1536. #endif
  1537. // Move the objects that are sent by value to the stack just before the call
  1538. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1539. {
  1540. if( descr->parameterTypes[n].IsReference() )
  1541. {
  1542. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1543. {
  1544. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1545. {
  1546. #ifdef AS_DEBUG
  1547. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1548. #endif
  1549. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1550. {
  1551. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1552. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1553. // as the value allocated on the stack is guaranteed to be safe
  1554. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1555. else
  1556. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1557. }
  1558. }
  1559. if( args[n]->type.dataType.IsObjectHandle() )
  1560. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1561. }
  1562. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1563. {
  1564. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1565. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1566. {
  1567. // Send the object as a reference to the object,
  1568. // and not to the variable holding the object
  1569. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1570. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1571. // as the value allocated on the stack is guaranteed to be safe
  1572. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1573. else
  1574. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1575. }
  1576. else
  1577. {
  1578. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1579. }
  1580. }
  1581. }
  1582. else if( descr->parameterTypes[n].IsObject() )
  1583. {
  1584. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1585. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1586. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1587. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1588. // The temporary variable must not be freed as it will no longer hold an object
  1589. DeallocateVariable(args[n]->type.stackOffset);
  1590. args[n]->type.isTemporary = false;
  1591. }
  1592. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1593. }
  1594. }
  1595. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1596. {
  1597. asASSERT(node->nodeType == snArgList);
  1598. // Count arguments
  1599. asCScriptNode *arg = node->firstChild;
  1600. int argCount = 0;
  1601. while( arg )
  1602. {
  1603. if( arg->nodeType != snNamedArgument )
  1604. argCount++;
  1605. arg = arg->next;
  1606. }
  1607. // Prepare the arrays
  1608. args.SetLength(argCount);
  1609. int n;
  1610. for( n = 0; n < argCount; n++ )
  1611. args[n] = 0;
  1612. n = argCount-1;
  1613. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1614. bool anyErrors = false, inPositionalArguments = false;
  1615. arg = node->lastChild;
  1616. while( arg )
  1617. {
  1618. asCScriptNode *asgNode = arg, *namedNode = 0;
  1619. if( asgNode->nodeType == snNamedArgument )
  1620. {
  1621. if( inPositionalArguments )
  1622. {
  1623. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1624. return -1;
  1625. }
  1626. asgNode = arg->firstChild->next;
  1627. namedNode = arg->firstChild;
  1628. asASSERT( namedNode->nodeType == snIdentifier );
  1629. }
  1630. else
  1631. inPositionalArguments = true;
  1632. asSExprContext expr(engine);
  1633. int r = CompileAssignment(asgNode, &expr);
  1634. if( r < 0 ) anyErrors = true;
  1635. asSExprContext *ctx = asNEW(asSExprContext)(engine);
  1636. if( ctx == 0 )
  1637. {
  1638. // Out of memory
  1639. return -1;
  1640. }
  1641. MergeExprBytecodeAndType(ctx, &expr);
  1642. if( inPositionalArguments )
  1643. {
  1644. args[n] = ctx;
  1645. n--;
  1646. }
  1647. else
  1648. {
  1649. asSNamedArgument namedArg;
  1650. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1651. namedArg.ctx = ctx;
  1652. // Error out when multiple arguments with the same name are passed
  1653. for( asUINT n = 0; n < namedArgs.GetLength(); ++n )
  1654. {
  1655. if( namedArgs[n].name == namedArg.name )
  1656. {
  1657. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1658. anyErrors = true;
  1659. break;
  1660. }
  1661. }
  1662. namedArgs.PushLast(namedArg);
  1663. }
  1664. arg = arg->prev;
  1665. }
  1666. return anyErrors ? -1 : 0;
  1667. }
  1668. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1669. {
  1670. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1671. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1672. return 0;
  1673. // Make sure to use the real function for virtual functions
  1674. if( func->funcType == asFUNC_VIRTUAL )
  1675. {
  1676. asASSERT( objectType );
  1677. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1678. }
  1679. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1680. bool anyErrors = false;
  1681. asCArray<int> varsUsed;
  1682. int explicitArgs = (int)args.GetLength();
  1683. for( int p = 0; p < explicitArgs; p++ )
  1684. args[p]->bc.GetVarsUsed(varsUsed);
  1685. // Make space for all the new arguments
  1686. args.SetLength(func->parameterTypes.GetLength());
  1687. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1688. args[c] = 0;
  1689. // Add the named arguments to the argument list in the right position
  1690. if( namedArgs )
  1691. {
  1692. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1693. {
  1694. asSNamedArgument &named = (*namedArgs)[n];
  1695. named.ctx->bc.GetVarsUsed(varsUsed);
  1696. //Find the right spot to put it in
  1697. asUINT index = asUINT(-1);
  1698. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1699. {
  1700. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1701. {
  1702. index = j;
  1703. break;
  1704. }
  1705. }
  1706. asASSERT( index < args.GetLength() );
  1707. args[index] = named.ctx;
  1708. named.ctx = 0;
  1709. }
  1710. }
  1711. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1712. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1713. {
  1714. if( args[n] != 0 ) continue;
  1715. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1716. // Parse the default arg string
  1717. asCParser parser(builder);
  1718. asCScriptCode code;
  1719. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1720. int r = parser.ParseExpression(&code);
  1721. if( r < 0 )
  1722. {
  1723. asCString msg;
  1724. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1725. Error(msg, node);
  1726. anyErrors = true;
  1727. continue;
  1728. }
  1729. asCScriptNode *arg = parser.GetScriptNode();
  1730. // Temporarily set the script code to the default arg expression
  1731. asCScriptCode *origScript = script;
  1732. script = &code;
  1733. // Don't allow the expression to access local variables
  1734. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function that is called
  1735. isCompilingDefaultArg = true;
  1736. asSExprContext expr(engine);
  1737. r = CompileExpression(arg, &expr);
  1738. // Don't allow address of class method
  1739. if( expr.methodName != "" )
  1740. {
  1741. // TODO: Improve error message
  1742. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1743. r = -1;
  1744. }
  1745. // Make sure the expression can be implicitly converted to the parameter type
  1746. if( r >= 0 )
  1747. {
  1748. asCArray<int> funcs;
  1749. funcs.PushLast(func->id);
  1750. asCArray<asSOverloadCandidate> matches;
  1751. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1752. {
  1753. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1754. r = -1;
  1755. }
  1756. }
  1757. isCompilingDefaultArg = false;
  1758. script = origScript;
  1759. if( r < 0 )
  1760. {
  1761. asCString msg;
  1762. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1763. Error(msg, node);
  1764. anyErrors = true;
  1765. continue;
  1766. }
  1767. args[n] = asNEW(asSExprContext)(engine);
  1768. if( args[n] == 0 )
  1769. {
  1770. // Out of memory
  1771. return -1;
  1772. }
  1773. MergeExprBytecodeAndType(args[n], &expr);
  1774. // Make sure the default arg expression doesn't end up
  1775. // with a variable that is used in a previous expression
  1776. if( args[n]->type.isVariable )
  1777. {
  1778. int offset = args[n]->type.stackOffset;
  1779. if( varsUsed.Exists(offset) )
  1780. {
  1781. // Release the current temporary variable
  1782. ReleaseTemporaryVariable(args[n]->type, 0);
  1783. asCDataType dt = args[n]->type.dataType;
  1784. dt.MakeReference(false);
  1785. // Reserve all variables already used in the expression so none of them will be used
  1786. asCArray<int> used;
  1787. args[n]->bc.GetVarsUsed(used);
  1788. size_t prevReserved = reservedVariables.GetLength();
  1789. reservedVariables.Concatenate(used);
  1790. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1791. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1792. reservedVariables.SetLength(prevReserved);
  1793. // Replace the variable in the expression
  1794. args[n]->bc.ExchangeVar(offset, newOffset);
  1795. args[n]->type.stackOffset = (short)newOffset;
  1796. args[n]->type.isTemporary = true;
  1797. args[n]->type.isVariable = true;
  1798. }
  1799. }
  1800. }
  1801. return anyErrors ? -1 : 0;
  1802. }
  1803. 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)
  1804. {
  1805. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1806. asUINT cost = 0;
  1807. asUINT n;
  1808. if( funcs.GetLength() > 0 )
  1809. {
  1810. // Check the number of parameters in the found functions
  1811. asUINT totalArgs = (asUINT)args.GetLength();
  1812. if( namedArgs != 0 )
  1813. totalArgs += (asUINT)namedArgs->GetLength();
  1814. for( n = 0; n < funcs.GetLength(); ++n )
  1815. {
  1816. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1817. if( desc->parameterTypes.GetLength() != totalArgs )
  1818. {
  1819. bool noMatch = true;
  1820. if( totalArgs < desc->parameterTypes.GetLength() )
  1821. {
  1822. // For virtual functions, the default args are defined in the real function of the object
  1823. if( desc->funcType == asFUNC_VIRTUAL )
  1824. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1825. // Count the number of default args
  1826. asUINT defaultArgs = 0;
  1827. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1828. if( desc->defaultArgs[d] )
  1829. defaultArgs++;
  1830. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1831. noMatch = false;
  1832. }
  1833. if( noMatch )
  1834. {
  1835. // remove it from the list
  1836. if( n == funcs.GetLength()-1 )
  1837. funcs.PopLast();
  1838. else
  1839. funcs[n] = funcs.PopLast();
  1840. n--;
  1841. }
  1842. }
  1843. }
  1844. // Match functions with the parameters, and discard those that do not match
  1845. asCArray<asSOverloadCandidate> matchingFuncs;
  1846. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1847. for ( n = 0; n < funcs.GetLength(); ++n )
  1848. {
  1849. matchingFuncs[n].funcId = funcs[n];
  1850. matchingFuncs[n].cost = 0;
  1851. }
  1852. // Match positionally passed arguments
  1853. for( n = 0; n < args.GetLength(); ++n )
  1854. {
  1855. asCArray<asSOverloadCandidate> tempFuncs;
  1856. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1857. // Intersect the found functions with the list of matching functions
  1858. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1859. {
  1860. asUINT c;
  1861. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1862. {
  1863. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1864. {
  1865. // Sum argument cost
  1866. matchingFuncs[f].cost += tempFuncs[c].cost;
  1867. break;
  1868. } // End if match
  1869. }
  1870. // Was the function a match?
  1871. if( c == tempFuncs.GetLength() )
  1872. {
  1873. // No, remove it from the list
  1874. if( f == matchingFuncs.GetLength()-1 )
  1875. matchingFuncs.PopLast();
  1876. else
  1877. matchingFuncs[f] = matchingFuncs.PopLast();
  1878. f--;
  1879. }
  1880. }
  1881. }
  1882. // Match named arguments
  1883. if( namedArgs != 0 )
  1884. {
  1885. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  1886. {
  1887. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  1888. if( desc->funcType == asFUNC_VIRTUAL )
  1889. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1890. //Match every named argument to an argument in the function
  1891. for( n = 0; n < namedArgs->GetLength(); ++n )
  1892. (*namedArgs)[n].match = asUINT(-1);
  1893. bool matchedAll = true;
  1894. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  1895. {
  1896. asUINT match = asUINT(-1);
  1897. for( n = 0; n < namedArgs->GetLength(); ++n )
  1898. {
  1899. asSNamedArgument &namedArg = (*namedArgs)[n];
  1900. if( desc->parameterNames[j] == namedArg.name )
  1901. {
  1902. namedArg.match = j;
  1903. match = n;
  1904. break;
  1905. }
  1906. }
  1907. // Check that every position is filled somehow
  1908. if( j >= args.GetLength() )
  1909. {
  1910. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  1911. {
  1912. // No argument was found for this, and there is no
  1913. // default, so it doesn't work.
  1914. matchedAll = false;
  1915. break;
  1916. }
  1917. }
  1918. else
  1919. {
  1920. if( match != asUINT(-1) )
  1921. {
  1922. // Can't name an argument that was already passed
  1923. matchedAll = false;
  1924. break;
  1925. }
  1926. }
  1927. }
  1928. //Check that every named argument was matched
  1929. if( matchedAll )
  1930. {
  1931. for( n = 0; n < namedArgs->GetLength(); ++n )
  1932. {
  1933. asSNamedArgument &named = (*namedArgs)[n];
  1934. if( named.match == asUINT(-1) )
  1935. {
  1936. matchedAll = false;
  1937. break;
  1938. }
  1939. // Add to the cost
  1940. asUINT cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  1941. if( cost == asUINT(-1) )
  1942. {
  1943. matchedAll = false;
  1944. break;
  1945. }
  1946. matchingFuncs[i].cost += cost;
  1947. }
  1948. }
  1949. if( !matchedAll )
  1950. {
  1951. // Remove the function, we didn't match all the arguments.
  1952. if( i == matchingFuncs.GetLength()-1 )
  1953. matchingFuncs.PopLast();
  1954. else
  1955. matchingFuncs[i] = matchingFuncs.PopLast();
  1956. i--;
  1957. }
  1958. }
  1959. }
  1960. // Select the overload(s) with the lowest overall cost
  1961. funcs.SetLength(0);
  1962. asUINT bestCost = asUINT(-1);
  1963. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  1964. {
  1965. cost = matchingFuncs[n].cost;
  1966. if( cost < bestCost )
  1967. {
  1968. funcs.SetLength(0);
  1969. bestCost = cost;
  1970. }
  1971. if( cost == bestCost )
  1972. funcs.PushLast( matchingFuncs[n].funcId );
  1973. }
  1974. // Cost returned is equivalent to the best cost discovered
  1975. cost = bestCost;
  1976. }
  1977. if( !isConstMethod )
  1978. FilterConst(funcs);
  1979. if( funcs.GetLength() != 1 && !silent )
  1980. {
  1981. // Build a readable string of the function with parameter types
  1982. bool attemptsPassingClassMethod = false;
  1983. asCString str;
  1984. if( scope != "" )
  1985. {
  1986. if( scope == "::" )
  1987. str = scope;
  1988. else
  1989. str = scope + "::";
  1990. }
  1991. str += name;
  1992. str += "(";
  1993. for( n = 0; n < args.GetLength(); n++ )
  1994. {
  1995. if( n > 0 )
  1996. str += ", ";
  1997. if( args[n]->methodName != "" )
  1998. {
  1999. if( args[n]->IsClassMethod() )
  2000. {
  2001. attemptsPassingClassMethod = true;
  2002. str += args[n]->type.dataType.GetObjectType()->GetName();
  2003. str += "::";
  2004. }
  2005. str += args[n]->methodName;
  2006. }
  2007. else
  2008. str += args[n]->type.dataType.Format();
  2009. }
  2010. if( namedArgs != 0 )
  2011. {
  2012. for( n = 0; n < namedArgs->GetLength(); n++ )
  2013. {
  2014. if( n > 0 || args.GetLength() )
  2015. str += ", ";
  2016. asSNamedArgument &named = (*namedArgs)[n];
  2017. str += named.name;
  2018. str += "=";
  2019. if( named.ctx->methodName != "" )
  2020. str += named.ctx->methodName;
  2021. else
  2022. str += named.ctx->type.dataType.Format();
  2023. }
  2024. }
  2025. str += ")";
  2026. if( isConstMethod )
  2027. str += " const";
  2028. if( objectType && scope == "" )
  2029. str = objectType->name + "::" + str;
  2030. if( funcs.GetLength() == 0 )
  2031. {
  2032. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2033. Error(str, node);
  2034. if( attemptsPassingClassMethod )
  2035. {
  2036. // Class methods must use delegate objects
  2037. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2038. }
  2039. else
  2040. {
  2041. // Print the list of candidates
  2042. if( origFuncs.GetLength() > 0 )
  2043. {
  2044. int r = 0, c = 0;
  2045. asASSERT( node );
  2046. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2047. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2048. PrintMatchingFuncs(origFuncs, node, objectType);
  2049. }
  2050. }
  2051. }
  2052. else
  2053. {
  2054. asASSERT( attemptsPassingClassMethod == false );
  2055. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2056. Error(str, node);
  2057. PrintMatchingFuncs(funcs, node, objectType);
  2058. }
  2059. }
  2060. return cost;
  2061. }
  2062. bool asCCompiler::CompileAutoType(asCDataType &type, asSExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2063. {
  2064. if( node && node->nodeType == snAssignment )
  2065. {
  2066. int r = CompileAssignment(node, &compiledCtx);
  2067. if( r >= 0 )
  2068. {
  2069. asCDataType newType = compiledCtx.type.dataType;
  2070. bool success = true;
  2071. // Handle const qualifier on auto
  2072. if( type.IsReadOnly() )
  2073. newType.MakeReadOnly(true);
  2074. else if( newType.IsPrimitive() )
  2075. newType.MakeReadOnly(false);
  2076. // Handle reference/value stuff
  2077. newType.MakeReference(false);
  2078. if( !newType.IsObjectHandle() )
  2079. {
  2080. // We got a value object or an object reference.
  2081. // Turn the variable into a handle if specified
  2082. // as auto@, otherwise make it a 'value'.
  2083. if( type.IsHandleToAuto() )
  2084. {
  2085. if( newType.MakeHandle(true) < 0 )
  2086. {
  2087. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2088. success = false;
  2089. }
  2090. }
  2091. }
  2092. if(success)
  2093. type = newType;
  2094. else
  2095. type = asCDataType::CreatePrimitive(ttInt, false);
  2096. return true;
  2097. }
  2098. return false;
  2099. }
  2100. else
  2101. {
  2102. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2103. type = asCDataType::CreatePrimitive(ttInt, false);
  2104. return false;
  2105. }
  2106. }
  2107. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2108. {
  2109. // Get the data type
  2110. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
  2111. // Declare all variables in this declaration
  2112. asCScriptNode *node = decl->firstChild->next;
  2113. while( node )
  2114. {
  2115. // If this is an auto type, we have to compile the assignment now to figure out the type
  2116. asSExprContext compiledCtx(engine);
  2117. bool preCompiled = false;
  2118. if( type.IsAuto() )
  2119. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2120. // Is the type allowed?
  2121. if( !type.CanBeInstantiated() )
  2122. {
  2123. asCString str;
  2124. if( type.IsAbstractClass() )
  2125. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf());
  2126. else if( type.IsInterface() )
  2127. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format().AddressOf());
  2128. else
  2129. // TODO: Improve error message to explain why
  2130. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  2131. Error(str, node);
  2132. // Use int instead to avoid further problems
  2133. type = asCDataType::CreatePrimitive(ttInt, false);
  2134. }
  2135. // A shared object may not declare variables of non-shared types
  2136. if( outFunc->IsShared() )
  2137. {
  2138. asCObjectType *ot = type.GetObjectType();
  2139. if( ot && !ot->IsShared() )
  2140. {
  2141. asCString msg;
  2142. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2143. Error(msg, decl);
  2144. }
  2145. }
  2146. // Get the name of the identifier
  2147. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2148. // Verify that the name isn't used by a dynamic data type
  2149. // TODO: Must check against registered funcdefs too
  2150. if( engine->GetRegisteredObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2151. {
  2152. asCString str;
  2153. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2154. Error(str, node);
  2155. }
  2156. int offset = AllocateVariable(type, false);
  2157. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2158. {
  2159. // TODO: It might be an out-of-memory too
  2160. asCString str;
  2161. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2162. Error(str, node);
  2163. // Don't continue after this error, as it will just
  2164. // lead to more errors that are likely false
  2165. return;
  2166. }
  2167. // Add marker that the variable has been declared
  2168. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2169. outFunc->AddVariable(name, type, offset);
  2170. // Keep the node for the variable decl
  2171. asCScriptNode *varNode = node;
  2172. node = node->next;
  2173. if( node == 0 || node->nodeType == snIdentifier )
  2174. {
  2175. // Initialize with default constructor
  2176. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2177. }
  2178. else
  2179. {
  2180. // Compile the initialization expression
  2181. asQWORD constantValue = 0;
  2182. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2183. {
  2184. // Check if the variable should be marked as pure constant
  2185. if( type.IsPrimitive() && type.IsReadOnly() )
  2186. {
  2187. sVariable *v = variables->GetVariable(name.AddressOf());
  2188. v->isPureConstant = true;
  2189. v->constantValue = constantValue;
  2190. }
  2191. }
  2192. node = node->next;
  2193. }
  2194. }
  2195. bc->OptimizeLocally(tempVariableOffsets);
  2196. }
  2197. // Returns true if the initialization expression is a constant expression
  2198. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asSExprContext *preCompiled)
  2199. {
  2200. bool isConstantExpression = false;
  2201. if( node && node->nodeType == snArgList )
  2202. {
  2203. // Make sure it is an object and not a handle
  2204. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  2205. {
  2206. Error(TXT_MUST_BE_OBJECT, node);
  2207. }
  2208. else
  2209. {
  2210. // Compile the arguments
  2211. asCArray<asSExprContext *> args;
  2212. asCArray<asSNamedArgument> namedArgs;
  2213. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2214. {
  2215. // Find all constructors
  2216. asCArray<int> funcs;
  2217. asSTypeBehaviour *beh = type.GetBehaviour();
  2218. if( beh )
  2219. {
  2220. if( type.GetObjectType()->flags & asOBJ_REF )
  2221. funcs = beh->factories;
  2222. else
  2223. funcs = beh->constructors;
  2224. }
  2225. asCString str = type.Format();
  2226. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2227. if( funcs.GetLength() == 1 )
  2228. {
  2229. // Add the default values for arguments not explicitly supplied
  2230. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], type.GetObjectType(), &namedArgs);
  2231. if( r == asSUCCESS )
  2232. {
  2233. asSExprContext ctx(engine);
  2234. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  2235. {
  2236. if( isVarGlobOrMem == 0 )
  2237. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2238. else
  2239. {
  2240. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2241. ctx.bc.Instr(asBC_RDSPtr);
  2242. if( isVarGlobOrMem == 1 )
  2243. {
  2244. // Store the returned handle in the global variable
  2245. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2246. }
  2247. else
  2248. {
  2249. // Store the returned handle in the member
  2250. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2251. ctx.bc.Instr(asBC_RDSPtr);
  2252. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2253. }
  2254. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  2255. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2256. }
  2257. // Pop the reference left by the function call
  2258. ctx.bc.Instr(asBC_PopPtr);
  2259. }
  2260. else
  2261. {
  2262. bool onHeap = false;
  2263. if( isVarGlobOrMem == 0 )
  2264. {
  2265. // When the object is allocated on the heap, the address where the
  2266. // reference will be stored must be pushed on the stack before the
  2267. // arguments. This reference on the stack is safe, even if the script
  2268. // is suspended during the evaluation of the arguments.
  2269. onHeap = IsVariableOnHeap(offset);
  2270. if( onHeap )
  2271. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2272. }
  2273. else if( isVarGlobOrMem == 1 )
  2274. {
  2275. // Push the address of the location where the variable will be stored on the stack.
  2276. // This reference is safe, because the addresses of the global variables cannot change.
  2277. onHeap = true;
  2278. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2279. }
  2280. else
  2281. {
  2282. // Value types may be allocated inline if they are POD types
  2283. onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
  2284. if( onHeap )
  2285. {
  2286. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2287. ctx.bc.Instr(asBC_RDSPtr);
  2288. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2289. }
  2290. }
  2291. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2292. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2293. // When the object is allocated on the stack, the address to the
  2294. // object is pushed on the stack after the arguments as the object pointer
  2295. if( !onHeap )
  2296. {
  2297. if( isVarGlobOrMem == 2 )
  2298. {
  2299. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2300. ctx.bc.Instr(asBC_RDSPtr);
  2301. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2302. }
  2303. else
  2304. {
  2305. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2306. }
  2307. }
  2308. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  2309. if( isVarGlobOrMem == 0 )
  2310. {
  2311. // Mark the object in the local variable as initialized
  2312. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2313. }
  2314. }
  2315. bc->AddCode(&ctx.bc);
  2316. }
  2317. }
  2318. }
  2319. // Cleanup
  2320. for( asUINT n = 0; n < args.GetLength(); n++ )
  2321. if( args[n] )
  2322. {
  2323. asDELETE(args[n],asSExprContext);
  2324. }
  2325. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2326. if( namedArgs[n].ctx )
  2327. {
  2328. asDELETE(namedArgs[n].ctx,asSExprContext);
  2329. }
  2330. }
  2331. }
  2332. else if( node && node->nodeType == snInitList )
  2333. {
  2334. asCTypeInfo ti;
  2335. ti.Set(type);
  2336. ti.isVariable = (isVarGlobOrMem == 0);
  2337. ti.isTemporary = false;
  2338. ti.stackOffset = (short)offset;
  2339. ti.isLValue = true;
  2340. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2341. }
  2342. else if( node && node->nodeType == snAssignment )
  2343. {
  2344. asSExprContext ctx(engine);
  2345. // TODO: copy: Here we should look for the best matching constructor, instead of
  2346. // just the copy constructor. Only if no appropriate constructor is
  2347. // available should the assignment operator be used.
  2348. // Compile the expression
  2349. asSExprContext newExpr(engine);
  2350. asSExprContext* expr;
  2351. int r = 0;
  2352. if( preCompiled )
  2353. {
  2354. expr = preCompiled;
  2355. }
  2356. else
  2357. {
  2358. expr = &newExpr;
  2359. r = CompileAssignment(node, expr);
  2360. }
  2361. // Call the default constructor here
  2362. if( isVarGlobOrMem == 0 )
  2363. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2364. else if( isVarGlobOrMem == 1 )
  2365. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2366. else if( isVarGlobOrMem == 2 )
  2367. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2368. if( r >= 0 )
  2369. {
  2370. if( type.IsPrimitive() )
  2371. {
  2372. if( type.IsReadOnly() && expr->type.isConstant )
  2373. {
  2374. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2375. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2376. isConstantExpression = true;
  2377. *constantValue = expr->type.qwordValue;
  2378. }
  2379. asSExprContext lctx(engine);
  2380. if( isVarGlobOrMem == 0 )
  2381. lctx.type.SetVariable(type, offset, false);
  2382. else if( isVarGlobOrMem == 1 )
  2383. {
  2384. lctx.type.Set(type);
  2385. lctx.type.dataType.MakeReference(true);
  2386. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2387. // we skip this as the bytecode won't be used anyway, only the constant value
  2388. if( offset >= 0 )
  2389. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2390. }
  2391. else
  2392. {
  2393. asASSERT( isVarGlobOrMem == 2 );
  2394. lctx.type.Set(type);
  2395. lctx.type.dataType.MakeReference(true);
  2396. // Load the reference of the primitive member into the register
  2397. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2398. lctx.bc.Instr(asBC_RDSPtr);
  2399. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2400. lctx.bc.Instr(asBC_PopRPtr);
  2401. }
  2402. lctx.type.dataType.MakeReadOnly(false);
  2403. lctx.type.isLValue = true;
  2404. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2405. ProcessDeferredParams(&ctx);
  2406. }
  2407. else
  2408. {
  2409. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2410. // just the copy constructor. Only if no appropriate constructor is
  2411. // available should the assignment operator be used.
  2412. asSExprContext lexpr(engine);
  2413. lexpr.type.Set(type);
  2414. if( isVarGlobOrMem == 0 )
  2415. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2416. else if( isVarGlobOrMem == 1 )
  2417. lexpr.type.dataType.MakeReference(true);
  2418. else if( isVarGlobOrMem == 2 )
  2419. {
  2420. if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) )
  2421. lexpr.type.dataType.MakeReference(true);
  2422. }
  2423. // Allow initialization of constant variables
  2424. lexpr.type.dataType.MakeReadOnly(false);
  2425. if( type.IsObjectHandle() )
  2426. lexpr.type.isExplicitHandle = true;
  2427. if( isVarGlobOrMem == 0 )
  2428. {
  2429. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2430. lexpr.type.stackOffset = (short)offset;
  2431. lexpr.type.isVariable = true;
  2432. }
  2433. else if( isVarGlobOrMem == 1 )
  2434. {
  2435. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2436. }
  2437. else
  2438. {
  2439. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2440. lexpr.bc.Instr(asBC_RDSPtr);
  2441. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2442. lexpr.type.stackOffset = -1;
  2443. }
  2444. lexpr.type.isLValue = true;
  2445. // If left expression resolves into a registered type
  2446. // check if the assignment operator is overloaded, and check
  2447. // the type of the right hand expression. If none is found
  2448. // the default action is a direct copy if it is the same type
  2449. // and a simple assignment.
  2450. bool assigned = false;
  2451. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2452. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  2453. {
  2454. bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType();
  2455. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, &ctx, useHndlAssign);
  2456. if( assigned )
  2457. {
  2458. // Pop the resulting value
  2459. if( !ctx.type.dataType.IsPrimitive() )
  2460. ctx.bc.Instr(asBC_PopPtr);
  2461. // Release the argument
  2462. ProcessDeferredParams(&ctx);
  2463. // Release temporary variable that may be allocated by the overloaded operator
  2464. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2465. }
  2466. }
  2467. if( !assigned )
  2468. {
  2469. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2470. // If the expression is constant and the variable also is constant
  2471. // then mark the variable as pure constant. This will allow the compiler
  2472. // to optimize expressions with this variable.
  2473. if( type.IsReadOnly() && expr->type.isConstant )
  2474. {
  2475. isConstantExpression = true;
  2476. *constantValue = expr->type.qwordValue;
  2477. }
  2478. // Add expression code to bytecode
  2479. MergeExprBytecode(&ctx, expr);
  2480. // Add byte code for storing value of expression in variable
  2481. ctx.bc.AddCode(&lexpr.bc);
  2482. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2483. // Release temporary variables used by expression
  2484. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2485. ctx.bc.Instr(asBC_PopPtr);
  2486. ProcessDeferredParams(&ctx);
  2487. }
  2488. }
  2489. }
  2490. bc->AddCode(&ctx.bc);
  2491. }
  2492. else
  2493. {
  2494. asASSERT( node == 0 );
  2495. // Call the default constructor here, as no explicit initialization is done
  2496. if( isVarGlobOrMem == 0 )
  2497. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2498. else if( isVarGlobOrMem == 1 )
  2499. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2500. else if( isVarGlobOrMem == 2 )
  2501. {
  2502. if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) )
  2503. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2504. else
  2505. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2506. }
  2507. }
  2508. return isConstantExpression;
  2509. }
  2510. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2511. {
  2512. // Check if the type supports initialization lists
  2513. if( var->dataType.GetObjectType() == 0 ||
  2514. var->dataType.GetBehaviour()->listFactory == 0 ||
  2515. var->dataType.IsObjectHandle() )
  2516. {
  2517. asCString str;
  2518. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  2519. Error(str, node);
  2520. return;
  2521. }
  2522. // Construct the buffer with the elements
  2523. // Find the list factory
  2524. int funcId = var->dataType.GetBehaviour()->listFactory;
  2525. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2526. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2527. // for small buffers so that the dynamic allocation is skipped
  2528. // Create a new special object type for the lists. Both asCRestore and the
  2529. // context exception handler will need this to know how to parse the buffer.
  2530. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2531. // Allocate a temporary variable to hold the pointer to the buffer
  2532. int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true);
  2533. asUINT bufferSize = 0;
  2534. // Evaluate all elements of the list
  2535. asSExprContext valueExpr(engine);
  2536. asCScriptNode *el = node;
  2537. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2538. int elementsInSubList = -1;
  2539. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2540. asASSERT( r || patternNode == 0 );
  2541. UNUSED_VAR(r);
  2542. // After all values have been evaluated we know the final size of the buffer
  2543. asSExprContext allocExpr(engine);
  2544. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2545. // Merge the bytecode into the final sequence
  2546. bc->AddCode(&allocExpr.bc);
  2547. bc->AddCode(&valueExpr.bc);
  2548. // The object itself is the last to be created and will receive the pointer to the buffer
  2549. asCArray<asSExprContext *> args;
  2550. asSExprContext arg1(engine);
  2551. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2552. arg1.type.dataType.MakeReference(true);
  2553. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2554. args.PushLast(&arg1);
  2555. asSExprContext ctx(engine);
  2556. if( var->isVariable )
  2557. {
  2558. asASSERT( isVarGlobOrMem == 0 );
  2559. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2560. {
  2561. ctx.bc.AddCode(&arg1.bc);
  2562. // Call factory and store the handle in the given variable
  2563. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2564. ctx.bc.Instr(asBC_PopPtr);
  2565. }
  2566. else
  2567. {
  2568. // Call the constructor
  2569. // When the object is allocated on the heap, the address where the
  2570. // reference will be stored must be pushed on the stack before the
  2571. // arguments. This reference on the stack is safe, even if the script
  2572. // is suspended during the evaluation of the arguments.
  2573. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2574. if( onHeap )
  2575. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2576. ctx.bc.AddCode(&arg1.bc);
  2577. // When the object is allocated on the stack, the address to the
  2578. // object is pushed on the stack after the arguments as the object pointer
  2579. if( !onHeap )
  2580. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2581. PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
  2582. // Mark the object in the local variable as initialized
  2583. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2584. }
  2585. }
  2586. else
  2587. {
  2588. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2589. {
  2590. ctx.bc.AddCode(&arg1.bc);
  2591. PerformFunctionCall(funcId, &ctx, false, &args);
  2592. ctx.bc.Instr(asBC_RDSPtr);
  2593. if( isVarGlobOrMem == 1 )
  2594. {
  2595. // Store the returned handle in the global variable
  2596. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2597. }
  2598. else
  2599. {
  2600. // Store the returned handle in the member
  2601. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2602. ctx.bc.Instr(asBC_RDSPtr);
  2603. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2604. }
  2605. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  2606. ctx.bc.Instr(asBC_PopPtr);
  2607. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2608. }
  2609. else
  2610. {
  2611. bool onHeap = true;
  2612. // Put the address where the object pointer will be placed on the stack
  2613. if( isVarGlobOrMem == 1 )
  2614. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2615. else
  2616. {
  2617. onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->flags & asOBJ_REF);
  2618. if( onHeap )
  2619. {
  2620. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2621. ctx.bc.Instr(asBC_RDSPtr);
  2622. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2623. }
  2624. }
  2625. // Add the address of the list buffer as the argument
  2626. ctx.bc.AddCode(&arg1.bc);
  2627. if( !onHeap )
  2628. {
  2629. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2630. ctx.bc.Instr(asBC_RDSPtr);
  2631. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2632. }
  2633. // Call the ALLOC instruction to allocate memory and invoke constructor
  2634. PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
  2635. }
  2636. }
  2637. bc->AddCode(&ctx.bc);
  2638. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2639. // each element in the buffer so there is no need to do this manually
  2640. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  2641. ReleaseTemporaryVariable(bufferVar, bc);
  2642. }
  2643. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList)
  2644. {
  2645. if( patternNode->type == asLPT_START )
  2646. {
  2647. if( valueNode->nodeType != snInitList )
  2648. {
  2649. Error(TXT_EXPECTED_LIST, valueNode);
  2650. return -1;
  2651. }
  2652. // Compile all values until asLPT_END
  2653. patternNode = patternNode->next;
  2654. asCScriptNode *node = valueNode->firstChild;
  2655. while( patternNode->type != asLPT_END )
  2656. {
  2657. if( node == 0 )
  2658. {
  2659. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  2660. return -1;
  2661. }
  2662. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode, elementsInSubList);
  2663. if( r < 0 ) return r;
  2664. asASSERT( patternNode );
  2665. }
  2666. if( node )
  2667. {
  2668. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  2669. return -1;
  2670. }
  2671. // Move to the next node
  2672. valueNode = valueNode->next;
  2673. patternNode = patternNode->next;
  2674. }
  2675. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  2676. {
  2677. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  2678. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  2679. asEListPatternNodeType repeatType = patternNode->type;
  2680. asCScriptNode *firstValue = valueNode;
  2681. // The following values will be repeated N times
  2682. patternNode = patternNode->next;
  2683. // Keep track of the patternNode so it can be reset
  2684. asSListPatternNode *nextNode = patternNode;
  2685. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  2686. if( bufferSize & 0x3 )
  2687. bufferSize += 4 - (bufferSize & 0x3);
  2688. // The first dword will hold the number of elements in the list
  2689. asDWORD currSize = bufferSize;
  2690. bufferSize += 4;
  2691. asUINT countElements = 0;
  2692. int elementsInSubSubList = -1;
  2693. asSExprContext ctx(engine);
  2694. while( valueNode )
  2695. {
  2696. patternNode = nextNode;
  2697. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  2698. if( r < 0 ) return r;
  2699. countElements++;
  2700. }
  2701. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  2702. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  2703. {
  2704. if( countElements < asUINT(elementsInSubList) )
  2705. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  2706. else
  2707. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  2708. return -1;
  2709. }
  2710. else
  2711. {
  2712. // Return to caller the amount of elments in this sublist
  2713. elementsInSubList = countElements;
  2714. }
  2715. // The first dword in the buffer will hold the number of elements
  2716. byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  2717. // Add the values
  2718. byteCode.AddCode(&ctx.bc);
  2719. }
  2720. else if( patternNode->type == asLPT_TYPE )
  2721. {
  2722. // Determine the size of the element
  2723. asUINT size = 0;
  2724. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  2725. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  2726. {
  2727. asSExprContext lctx(engine);
  2728. asSExprContext rctx(engine);
  2729. if( valueNode->nodeType == snAssignment )
  2730. {
  2731. // Compile the assignment expression
  2732. CompileAssignment(valueNode, &rctx);
  2733. if( dt.GetTokenType() == ttQuestion )
  2734. {
  2735. // We now know the type
  2736. dt = rctx.type.dataType;
  2737. dt.MakeReadOnly(false);
  2738. dt.MakeReference(false);
  2739. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2740. if( bufferSize & 0x3 )
  2741. bufferSize += 4 - (bufferSize & 0x3);
  2742. // Place the type id in the buffer
  2743. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  2744. bufferSize += 4;
  2745. }
  2746. }
  2747. else if( valueNode->nodeType == snInitList )
  2748. {
  2749. if( dt.GetTokenType() == ttQuestion )
  2750. {
  2751. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  2752. asCString str;
  2753. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  2754. Error(str.AddressOf(), valueNode);
  2755. rctx.type.SetDummy();
  2756. dt = rctx.type.dataType;
  2757. }
  2758. else
  2759. {
  2760. // Allocate a temporary variable that will be initialized with the list
  2761. int offset = AllocateVariable(dt, true);
  2762. rctx.type.Set(dt);
  2763. rctx.type.isVariable = true;
  2764. rctx.type.isTemporary = true;
  2765. rctx.type.stackOffset = (short)offset;
  2766. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  2767. // Put the object on the stack
  2768. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  2769. // It is a reference that we place on the stack
  2770. rctx.type.dataType.MakeReference(true);
  2771. }
  2772. }
  2773. // Determine size of the element
  2774. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2775. size = dt.GetSizeInMemoryBytes();
  2776. else
  2777. size = AS_PTR_SIZE*4;
  2778. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2779. if( size >= 4 && (bufferSize & 0x3) )
  2780. bufferSize += 4 - (bufferSize & 0x3);
  2781. // Compile the lvalue
  2782. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2783. lctx.type.Set(dt);
  2784. lctx.type.isLValue = true;
  2785. if( dt.IsPrimitive() )
  2786. {
  2787. lctx.bc.Instr(asBC_PopRPtr);
  2788. lctx.type.dataType.MakeReference(true);
  2789. }
  2790. else if( dt.IsObjectHandle() ||
  2791. dt.GetObjectType()->flags & asOBJ_REF )
  2792. {
  2793. lctx.type.isExplicitHandle = true;
  2794. lctx.type.dataType.MakeReference(true);
  2795. }
  2796. else
  2797. {
  2798. asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE );
  2799. // Make sure the object has been constructed before the assignment
  2800. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  2801. asSTypeBehaviour *beh = dt.GetBehaviour();
  2802. int func = 0;
  2803. if( beh ) func = beh->construct;
  2804. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2805. {
  2806. asCString str;
  2807. // TODO: funcdef: asCDataType should have a GetTypeName()
  2808. if( dt.GetFuncDef() )
  2809. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2810. else
  2811. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2812. Error(str, valueNode);
  2813. }
  2814. else if( func )
  2815. {
  2816. // Call the constructor as a normal function
  2817. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2818. asSExprContext ctx(engine);
  2819. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  2820. byteCode.AddCode(&ctx.bc);
  2821. }
  2822. }
  2823. asSExprContext ctx(engine);
  2824. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  2825. if( !lctx.type.dataType.IsPrimitive() )
  2826. ctx.bc.Instr(asBC_PopPtr);
  2827. // Release temporary variables used by expression
  2828. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2829. ProcessDeferredParams(&ctx);
  2830. byteCode.AddCode(&ctx.bc);
  2831. }
  2832. else
  2833. {
  2834. // There is no specific value so we need to fill it with a default value
  2835. if( dt.GetTokenType() == ttQuestion )
  2836. {
  2837. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2838. if( bufferSize & 0x3 )
  2839. bufferSize += 4 - (bufferSize & 0x3);
  2840. // Place the type id for a null handle in the buffer
  2841. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  2842. bufferSize += 4;
  2843. dt = asCDataType::CreateNullHandle();
  2844. // No need to initialize the handle as the buffer is already initialized with zeroes
  2845. }
  2846. else if( dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_VALUE )
  2847. {
  2848. // For value types with default constructor we need to call the constructor
  2849. asSTypeBehaviour *beh = dt.GetBehaviour();
  2850. int func = 0;
  2851. if( beh ) func = beh->construct;
  2852. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2853. {
  2854. asCString str;
  2855. // TODO: funcdef: asCDataType should have a GetTypeName()
  2856. if( dt.GetFuncDef() )
  2857. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2858. else
  2859. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2860. Error(str, valueNode);
  2861. }
  2862. else if( func )
  2863. {
  2864. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2865. if( bufferSize & 0x3 )
  2866. bufferSize += 4 - (bufferSize & 0x3);
  2867. // Call the constructor as a normal function
  2868. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2869. asSExprContext ctx(engine);
  2870. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  2871. byteCode.AddCode(&ctx.bc);
  2872. }
  2873. }
  2874. else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF )
  2875. {
  2876. // For ref types (not handles) we need to call the default factory
  2877. asSTypeBehaviour *beh = dt.GetBehaviour();
  2878. int func = 0;
  2879. if( beh ) func = beh->factory;
  2880. if( func == 0 )
  2881. {
  2882. asCString str;
  2883. // TODO: funcdef: asCDataType should have a GetTypeName()
  2884. if( dt.GetFuncDef() )
  2885. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2886. else
  2887. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2888. Error(str, valueNode);
  2889. }
  2890. else if( func )
  2891. {
  2892. asSExprContext rctx(engine);
  2893. PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType());
  2894. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2895. if( bufferSize & 0x3 )
  2896. bufferSize += 4 - (bufferSize & 0x3);
  2897. asSExprContext lctx(engine);
  2898. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2899. lctx.type.Set(dt);
  2900. lctx.type.isLValue = true;
  2901. lctx.type.isExplicitHandle = true;
  2902. lctx.type.dataType.MakeReference(true);
  2903. asSExprContext ctx(engine);
  2904. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  2905. if( !lctx.type.dataType.IsPrimitive() )
  2906. ctx.bc.Instr(asBC_PopPtr);
  2907. // Release temporary variables used by expression
  2908. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2909. ProcessDeferredParams(&ctx);
  2910. byteCode.AddCode(&ctx.bc);
  2911. }
  2912. }
  2913. }
  2914. // Determine size of the element
  2915. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2916. size = dt.GetSizeInMemoryBytes();
  2917. else
  2918. size = AS_PTR_SIZE*4;
  2919. asASSERT( size <= 4 || (size & 0x3) == 0 );
  2920. // Move to the next element
  2921. bufferSize += size;
  2922. patternNode = patternNode->next;
  2923. valueNode = valueNode->next;
  2924. }
  2925. else
  2926. asASSERT( false );
  2927. return 0;
  2928. }
  2929. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  2930. {
  2931. // Don't clear the hasReturn flag if this is an empty statement
  2932. // to avoid false errors of 'not all paths return'
  2933. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  2934. *hasReturn = false;
  2935. if( statement->nodeType == snStatementBlock )
  2936. CompileStatementBlock(statement, true, hasReturn, bc);
  2937. else if( statement->nodeType == snIf )
  2938. CompileIfStatement(statement, hasReturn, bc);
  2939. else if( statement->nodeType == snFor )
  2940. CompileForStatement(statement, bc);
  2941. else if( statement->nodeType == snWhile )
  2942. CompileWhileStatement(statement, bc);
  2943. else if( statement->nodeType == snDoWhile )
  2944. CompileDoWhileStatement(statement, bc);
  2945. else if( statement->nodeType == snExpressionStatement )
  2946. CompileExpressionStatement(statement, bc);
  2947. else if( statement->nodeType == snBreak )
  2948. CompileBreakStatement(statement, bc);
  2949. else if( statement->nodeType == snContinue )
  2950. CompileContinueStatement(statement, bc);
  2951. else if( statement->nodeType == snSwitch )
  2952. CompileSwitchStatement(statement, hasReturn, bc);
  2953. else if( statement->nodeType == snReturn )
  2954. {
  2955. CompileReturnStatement(statement, bc);
  2956. *hasReturn = true;
  2957. }
  2958. }
  2959. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  2960. {
  2961. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  2962. // Reserve label for break statements
  2963. int breakLabel = nextLabel++;
  2964. breakLabels.PushLast(breakLabel);
  2965. // Add a variable scope that will be used by CompileBreak
  2966. // to know where to stop deallocating variables
  2967. AddVariableScope(true, false);
  2968. //---------------------------
  2969. // Compile the switch expression
  2970. //-------------------------------
  2971. // Compile the switch expression
  2972. asSExprContext expr(engine);
  2973. CompileAssignment(snode->firstChild, &expr);
  2974. // Verify that the expression is a primitive type
  2975. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  2976. {
  2977. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  2978. return;
  2979. }
  2980. ProcessPropertyGetAccessor(&expr, snode);
  2981. // TODO: Need to support 64bit integers
  2982. // Convert the expression to a 32bit variable
  2983. asCDataType to;
  2984. if( expr.type.dataType.IsIntegerType() )
  2985. to.SetTokenType(ttInt);
  2986. else if( expr.type.dataType.IsUnsignedType() )
  2987. to.SetTokenType(ttUInt);
  2988. // Make sure the value is in a variable
  2989. if( expr.type.dataType.IsReference() )
  2990. ConvertToVariable(&expr);
  2991. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  2992. ConvertToVariable(&expr);
  2993. int offset = expr.type.stackOffset;
  2994. ProcessDeferredParams(&expr);
  2995. //-------------------------------
  2996. // Determine case values and labels
  2997. //--------------------------------
  2998. // Remember the first label so that we can later pass the
  2999. // correct label to each CompileCase()
  3000. int firstCaseLabel = nextLabel;
  3001. int defaultLabel = 0;
  3002. asCArray<int> caseValues;
  3003. asCArray<int> caseLabels;
  3004. // Compile all case comparisons and make them jump to the right label
  3005. asCScriptNode *cnode = snode->firstChild->next;
  3006. while( cnode )
  3007. {
  3008. // Each case should have a constant expression
  3009. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3010. {
  3011. // Compile expression
  3012. asSExprContext c(engine);
  3013. CompileExpression(cnode->firstChild, &c);
  3014. // Verify that the result is a constant
  3015. if( !c.type.isConstant )
  3016. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3017. // Verify that the result is an integral number
  3018. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
  3019. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3020. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3021. // Has this case been declared already?
  3022. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  3023. {
  3024. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3025. }
  3026. // TODO: Optimize: We can insert the numbers sorted already
  3027. // Store constant for later use
  3028. caseValues.PushLast(c.type.intValue);
  3029. // Reserve label for this case
  3030. caseLabels.PushLast(nextLabel++);
  3031. }
  3032. else
  3033. {
  3034. // TODO: It shouldn't be necessary for the default case to be the last one.
  3035. // Is default the last case?
  3036. if( cnode->next )
  3037. {
  3038. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3039. break;
  3040. }
  3041. // Reserve label for this case
  3042. defaultLabel = nextLabel++;
  3043. }
  3044. cnode = cnode->next;
  3045. }
  3046. // check for empty switch
  3047. if (caseValues.GetLength() == 0)
  3048. {
  3049. Error(TXT_EMPTY_SWITCH, snode);
  3050. return;
  3051. }
  3052. if( defaultLabel == 0 )
  3053. defaultLabel = breakLabel;
  3054. //---------------------------------
  3055. // Output the optimized case comparisons
  3056. // with jumps to the case code
  3057. //------------------------------------
  3058. // Sort the case values by increasing value. Do the sort together with the labels
  3059. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3060. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3061. {
  3062. for( int bck = fwd - 1; bck >= 0; bck-- )
  3063. {
  3064. int bckp = bck + 1;
  3065. if( caseValues[bck] > caseValues[bckp] )
  3066. {
  3067. // Swap the values in both arrays
  3068. int swap = caseValues[bckp];
  3069. caseValues[bckp] = caseValues[bck];
  3070. caseValues[bck] = swap;
  3071. swap = caseLabels[bckp];
  3072. caseLabels[bckp] = caseLabels[bck];
  3073. caseLabels[bck] = swap;
  3074. }
  3075. else
  3076. break;
  3077. }
  3078. }
  3079. // Find ranges of consecutive numbers
  3080. asCArray<int> ranges;
  3081. ranges.PushLast(0);
  3082. asUINT n;
  3083. for( n = 1; n < caseValues.GetLength(); ++n )
  3084. {
  3085. // We can join numbers that are less than 5 numbers
  3086. // apart since the output code will still be smaller
  3087. if( caseValues[n] > caseValues[n-1] + 5 )
  3088. ranges.PushLast(n);
  3089. }
  3090. // If the value is larger than the largest case value, jump to default
  3091. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3092. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3093. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3094. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3095. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3096. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3097. // binary search instead of a linear search through the ranges
  3098. // For each range
  3099. int range;
  3100. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3101. {
  3102. // Find the largest value in this range
  3103. int maxRange = caseValues[ranges[range]];
  3104. int index = ranges[range];
  3105. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3106. maxRange = caseValues[index];
  3107. // If there are only 2 numbers then it is better to compare them directly
  3108. if( index - ranges[range] > 2 )
  3109. {
  3110. // If the value is smaller than the smallest case value in the range, jump to default
  3111. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3112. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3113. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3114. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3115. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3116. int nextRangeLabel = nextLabel++;
  3117. // If this is the last range we don't have to make this test
  3118. if( range < (int)ranges.GetLength() - 1 )
  3119. {
  3120. // If the value is larger than the largest case value in the range, jump to the next range
  3121. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3122. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3123. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3124. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3125. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3126. }
  3127. // Jump forward according to the value
  3128. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3129. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3130. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3131. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3132. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3133. // Add the list of jumps to the correct labels (any holes, jump to default)
  3134. index = ranges[range];
  3135. for( int n = caseValues[index]; n <= maxRange; n++ )
  3136. {
  3137. if( caseValues[index] == n )
  3138. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3139. else
  3140. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3141. }
  3142. expr.bc.Label((short)nextRangeLabel);
  3143. }
  3144. else
  3145. {
  3146. // Simply make a comparison with each value
  3147. int n;
  3148. for( n = ranges[range]; n < index; ++n )
  3149. {
  3150. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3151. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  3152. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3153. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  3154. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3155. }
  3156. }
  3157. }
  3158. // Catch any value that falls trough
  3159. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3160. // Release the temporary variable previously stored
  3161. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3162. // TODO: optimize: Should optimize each piece individually
  3163. expr.bc.OptimizeLocally(tempVariableOffsets);
  3164. //----------------------------------
  3165. // Output case implementations
  3166. //----------------------------------
  3167. // Compile case implementations, each one with the label before it
  3168. cnode = snode->firstChild->next;
  3169. while( cnode )
  3170. {
  3171. // Each case should have a constant expression
  3172. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3173. {
  3174. expr.bc.Label((short)firstCaseLabel++);
  3175. CompileCase(cnode->firstChild->next, &expr.bc);
  3176. }
  3177. else
  3178. {
  3179. expr.bc.Label((short)defaultLabel);
  3180. // Is default the last case?
  3181. if( cnode->next )
  3182. {
  3183. // We've already reported this error
  3184. break;
  3185. }
  3186. CompileCase(cnode->firstChild, &expr.bc);
  3187. }
  3188. cnode = cnode->next;
  3189. }
  3190. //--------------------------------
  3191. bc->AddCode(&expr.bc);
  3192. // Add break label
  3193. bc->Label((short)breakLabel);
  3194. breakLabels.PopLast();
  3195. RemoveVariableScope();
  3196. }
  3197. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3198. {
  3199. bool isFinished = false;
  3200. bool hasReturn = false;
  3201. bool hasUnreachableCode = false;
  3202. while( node )
  3203. {
  3204. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3205. {
  3206. hasUnreachableCode = true;
  3207. Warning(TXT_UNREACHABLE_CODE, node);
  3208. break;
  3209. }
  3210. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3211. isFinished = true;
  3212. asCByteCode statement(engine);
  3213. if( node->nodeType == snDeclaration )
  3214. {
  3215. Error(TXT_DECL_IN_SWITCH, node);
  3216. // Compile it anyway to avoid further compiler errors
  3217. CompileDeclaration(node, &statement);
  3218. }
  3219. else
  3220. CompileStatement(node, &hasReturn, &statement);
  3221. LineInstr(bc, node->tokenPos);
  3222. bc->AddCode(&statement);
  3223. if( !hasCompileErrors )
  3224. asASSERT( tempVariables.GetLength() == 0 );
  3225. node = node->next;
  3226. }
  3227. }
  3228. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3229. {
  3230. // We will use one label for the if statement
  3231. // and possibly another for the else statement
  3232. int afterLabel = nextLabel++;
  3233. // Compile the expression
  3234. asSExprContext expr(engine);
  3235. int r = CompileAssignment(inode->firstChild, &expr);
  3236. if( r == 0 )
  3237. {
  3238. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3239. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3240. else
  3241. {
  3242. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3243. ProcessDeferredParams(&expr);
  3244. if( !expr.type.isConstant )
  3245. {
  3246. ProcessPropertyGetAccessor(&expr, inode);
  3247. ConvertToVariable(&expr);
  3248. // Add a test
  3249. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3250. expr.bc.Instr(asBC_ClrHi);
  3251. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3252. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3253. expr.bc.OptimizeLocally(tempVariableOffsets);
  3254. bc->AddCode(&expr.bc);
  3255. }
  3256. else if( expr.type.dwordValue == 0 )
  3257. {
  3258. // Jump to the else case
  3259. bc->InstrINT(asBC_JMP, afterLabel);
  3260. // TODO: Should we warn that the expression will always go to the else?
  3261. }
  3262. }
  3263. }
  3264. // Compile the if statement
  3265. bool origIsConstructorCalled = m_isConstructorCalled;
  3266. bool hasReturn1;
  3267. asCByteCode ifBC(engine);
  3268. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3269. // Add the byte code
  3270. LineInstr(bc, inode->firstChild->next->tokenPos);
  3271. bc->AddCode(&ifBC);
  3272. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3273. {
  3274. // Don't allow if( expr );
  3275. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3276. }
  3277. // If one of the statements call the constructor, the other must as well
  3278. // otherwise it is possible the constructor is never called
  3279. bool constructorCall1 = false;
  3280. bool constructorCall2 = false;
  3281. if( !origIsConstructorCalled && m_isConstructorCalled )
  3282. constructorCall1 = true;
  3283. // Do we have an else statement?
  3284. if( inode->firstChild->next != inode->lastChild )
  3285. {
  3286. // Reset the constructor called flag so the else statement can call the constructor too
  3287. m_isConstructorCalled = origIsConstructorCalled;
  3288. int afterElse = 0;
  3289. if( !hasReturn1 )
  3290. {
  3291. afterElse = nextLabel++;
  3292. // Add jump to after the else statement
  3293. bc->InstrINT(asBC_JMP, afterElse);
  3294. }
  3295. // Add label for the else statement
  3296. bc->Label((short)afterLabel);
  3297. bool hasReturn2;
  3298. asCByteCode elseBC(engine);
  3299. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3300. // Add byte code for the else statement
  3301. LineInstr(bc, inode->lastChild->tokenPos);
  3302. bc->AddCode(&elseBC);
  3303. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3304. {
  3305. // Don't allow if( expr ) {} else;
  3306. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3307. }
  3308. if( !hasReturn1 )
  3309. {
  3310. // Add label for the end of else statement
  3311. bc->Label((short)afterElse);
  3312. }
  3313. // The if statement only has return if both alternatives have
  3314. *hasReturn = hasReturn1 && hasReturn2;
  3315. if( !origIsConstructorCalled && m_isConstructorCalled )
  3316. constructorCall2 = true;
  3317. }
  3318. else
  3319. {
  3320. // Add label for the end of if statement
  3321. bc->Label((short)afterLabel);
  3322. *hasReturn = false;
  3323. }
  3324. // Make sure both or neither conditions call a constructor
  3325. if( (constructorCall1 && !constructorCall2) ||
  3326. (constructorCall2 && !constructorCall1) )
  3327. {
  3328. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3329. }
  3330. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3331. }
  3332. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3333. {
  3334. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3335. AddVariableScope(true, true);
  3336. // We will use three labels for the for loop
  3337. int conditionLabel = nextLabel++;
  3338. int afterLabel = nextLabel++;
  3339. int continueLabel = nextLabel++;
  3340. int insideLabel = nextLabel++;
  3341. continueLabels.PushLast(continueLabel);
  3342. breakLabels.PushLast(afterLabel);
  3343. //---------------------------------------
  3344. // Compile the initialization statement
  3345. asCByteCode initBC(engine);
  3346. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3347. if( fnode->firstChild->nodeType == snDeclaration )
  3348. CompileDeclaration(fnode->firstChild, &initBC);
  3349. else
  3350. CompileExpressionStatement(fnode->firstChild, &initBC);
  3351. //-----------------------------------
  3352. // Compile the condition statement
  3353. asSExprContext expr(engine);
  3354. asCScriptNode *second = fnode->firstChild->next;
  3355. if( second->firstChild )
  3356. {
  3357. int r = CompileAssignment(second->firstChild, &expr);
  3358. if( r >= 0 )
  3359. {
  3360. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3361. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3362. else
  3363. {
  3364. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3365. ProcessDeferredParams(&expr);
  3366. ProcessPropertyGetAccessor(&expr, second);
  3367. // If expression is false exit the loop
  3368. ConvertToVariable(&expr);
  3369. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3370. expr.bc.Instr(asBC_ClrHi);
  3371. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3372. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3373. expr.bc.OptimizeLocally(tempVariableOffsets);
  3374. // Prepend the line instruction for the condition
  3375. asCByteCode tmp(engine);
  3376. LineInstr(&tmp, second->firstChild->tokenPos);
  3377. tmp.AddCode(&expr.bc);
  3378. expr.bc.AddCode(&tmp);
  3379. }
  3380. }
  3381. }
  3382. //---------------------------
  3383. // Compile the increment statement
  3384. asCByteCode nextBC(engine);
  3385. asCScriptNode *third = second->next;
  3386. if( third->nodeType == snExpressionStatement )
  3387. {
  3388. LineInstr(&nextBC, third->tokenPos);
  3389. CompileExpressionStatement(third, &nextBC);
  3390. }
  3391. //------------------------------
  3392. // Compile loop statement
  3393. bool hasReturn;
  3394. asCByteCode forBC(engine);
  3395. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3396. //-------------------------------
  3397. // Join the code pieces
  3398. bc->AddCode(&initBC);
  3399. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3400. bc->Label((short)insideLabel);
  3401. // Add a suspend bytecode inside the loop to guarantee
  3402. // that the application can suspend the execution
  3403. bc->Instr(asBC_SUSPEND);
  3404. bc->InstrPTR(asBC_JitEntry, 0);
  3405. LineInstr(bc, fnode->lastChild->tokenPos);
  3406. bc->AddCode(&forBC);
  3407. bc->Label((short)continueLabel);
  3408. bc->AddCode(&nextBC);
  3409. bc->Label((short)conditionLabel);
  3410. if( expr.bc.GetLastInstr() == -1 )
  3411. // There is no condition, so we just always jump
  3412. bc->InstrDWORD(asBC_JMP, insideLabel);
  3413. else
  3414. bc->AddCode(&expr.bc);
  3415. bc->Label((short)afterLabel);
  3416. continueLabels.PopLast();
  3417. breakLabels.PopLast();
  3418. // Deallocate variables in this block, in reverse order
  3419. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3420. {
  3421. sVariable *v = variables->variables[n];
  3422. // Call variable destructors here, for variables not yet destroyed
  3423. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3424. // Don't deallocate function parameters
  3425. if( v->stackOffset > 0 )
  3426. DeallocateVariable(v->stackOffset);
  3427. }
  3428. RemoveVariableScope();
  3429. }
  3430. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3431. {
  3432. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3433. AddVariableScope(true, true);
  3434. // We will use two labels for the while loop
  3435. int beforeLabel = nextLabel++;
  3436. int afterLabel = nextLabel++;
  3437. continueLabels.PushLast(beforeLabel);
  3438. breakLabels.PushLast(afterLabel);
  3439. // Add label before the expression
  3440. bc->Label((short)beforeLabel);
  3441. // Compile expression
  3442. asSExprContext expr(engine);
  3443. int r = CompileAssignment(wnode->firstChild, &expr);
  3444. if( r == 0 )
  3445. {
  3446. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3447. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3448. else
  3449. {
  3450. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3451. ProcessDeferredParams(&expr);
  3452. ProcessPropertyGetAccessor(&expr, wnode);
  3453. // Add byte code for the expression
  3454. ConvertToVariable(&expr);
  3455. // Jump to end of statement if expression is false
  3456. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3457. expr.bc.Instr(asBC_ClrHi);
  3458. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3459. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3460. expr.bc.OptimizeLocally(tempVariableOffsets);
  3461. bc->AddCode(&expr.bc);
  3462. }
  3463. }
  3464. // Add a suspend bytecode inside the loop to guarantee
  3465. // that the application can suspend the execution
  3466. bc->Instr(asBC_SUSPEND);
  3467. bc->InstrPTR(asBC_JitEntry, 0);
  3468. // Compile statement
  3469. bool hasReturn;
  3470. asCByteCode whileBC(engine);
  3471. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3472. // Add byte code for the statement
  3473. LineInstr(bc, wnode->lastChild->tokenPos);
  3474. bc->AddCode(&whileBC);
  3475. // Jump to the expression
  3476. bc->InstrINT(asBC_JMP, beforeLabel);
  3477. // Add label after the statement
  3478. bc->Label((short)afterLabel);
  3479. continueLabels.PopLast();
  3480. breakLabels.PopLast();
  3481. RemoveVariableScope();
  3482. }
  3483. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3484. {
  3485. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3486. AddVariableScope(true, true);
  3487. // We will use two labels for the while loop
  3488. int beforeLabel = nextLabel++;
  3489. int beforeTest = nextLabel++;
  3490. int afterLabel = nextLabel++;
  3491. continueLabels.PushLast(beforeTest);
  3492. breakLabels.PushLast(afterLabel);
  3493. // Add label before the statement
  3494. bc->Label((short)beforeLabel);
  3495. // Compile statement
  3496. bool hasReturn;
  3497. asCByteCode whileBC(engine);
  3498. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3499. // Add byte code for the statement
  3500. LineInstr(bc, wnode->firstChild->tokenPos);
  3501. bc->AddCode(&whileBC);
  3502. // Add label before the expression
  3503. bc->Label((short)beforeTest);
  3504. // Add a suspend bytecode inside the loop to guarantee
  3505. // that the application can suspend the execution
  3506. bc->Instr(asBC_SUSPEND);
  3507. bc->InstrPTR(asBC_JitEntry, 0);
  3508. // Add a line instruction
  3509. LineInstr(bc, wnode->lastChild->tokenPos);
  3510. // Compile expression
  3511. asSExprContext expr(engine);
  3512. CompileAssignment(wnode->lastChild, &expr);
  3513. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3514. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3515. else
  3516. {
  3517. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3518. ProcessDeferredParams(&expr);
  3519. ProcessPropertyGetAccessor(&expr, wnode);
  3520. // Add byte code for the expression
  3521. ConvertToVariable(&expr);
  3522. // Jump to next iteration if expression is true
  3523. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3524. expr.bc.Instr(asBC_ClrHi);
  3525. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3526. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3527. expr.bc.OptimizeLocally(tempVariableOffsets);
  3528. bc->AddCode(&expr.bc);
  3529. }
  3530. // Add label after the statement
  3531. bc->Label((short)afterLabel);
  3532. continueLabels.PopLast();
  3533. breakLabels.PopLast();
  3534. RemoveVariableScope();
  3535. }
  3536. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3537. {
  3538. if( breakLabels.GetLength() == 0 )
  3539. {
  3540. Error(TXT_INVALID_BREAK, node);
  3541. return;
  3542. }
  3543. // Add destructor calls for all variables that will go out of scope
  3544. // Put this clean up in a block to allow exception handler to understand them
  3545. bc->Block(true);
  3546. asCVariableScope *vs = variables;
  3547. while( !vs->isBreakScope )
  3548. {
  3549. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3550. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3551. vs = vs->parent;
  3552. }
  3553. bc->Block(false);
  3554. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  3555. }
  3556. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  3557. {
  3558. if( continueLabels.GetLength() == 0 )
  3559. {
  3560. Error(TXT_INVALID_CONTINUE, node);
  3561. return;
  3562. }
  3563. // Add destructor calls for all variables that will go out of scope
  3564. // Put this clean up in a block to allow exception handler to understand them
  3565. bc->Block(true);
  3566. asCVariableScope *vs = variables;
  3567. while( !vs->isContinueScope )
  3568. {
  3569. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3570. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3571. vs = vs->parent;
  3572. }
  3573. bc->Block(false);
  3574. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  3575. }
  3576. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  3577. {
  3578. if( enode->firstChild )
  3579. {
  3580. // Compile the expression
  3581. asSExprContext expr(engine);
  3582. CompileAssignment(enode->firstChild, &expr);
  3583. // Must not have unused ambiguous names
  3584. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  3585. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  3586. // If we get here and there is still an unprocessed property
  3587. // accessor, then process it as a get access. Don't call if there is
  3588. // already a compile error, or we might report an error that is not valid
  3589. if( !hasCompileErrors )
  3590. ProcessPropertyGetAccessor(&expr, enode);
  3591. // Pop the value from the stack
  3592. if( !expr.type.dataType.IsPrimitive() )
  3593. expr.bc.Instr(asBC_PopPtr);
  3594. // Release temporary variables used by expression
  3595. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3596. ProcessDeferredParams(&expr);
  3597. expr.bc.OptimizeLocally(tempVariableOffsets);
  3598. bc->AddCode(&expr.bc);
  3599. }
  3600. }
  3601. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  3602. {
  3603. // If the object already is stored in temporary variable then nothing needs to be done
  3604. // Note, a type can be temporary without being a variable, in which case it is holding off
  3605. // on releasing a previously used object.
  3606. if( ctx->type.isTemporary && ctx->type.isVariable &&
  3607. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  3608. {
  3609. // If the temporary object is currently not a reference
  3610. // the expression needs to be reevaluated to a reference
  3611. if( !ctx->type.dataType.IsReference() )
  3612. {
  3613. ctx->bc.Instr(asBC_PopPtr);
  3614. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3615. ctx->type.dataType.MakeReference(true);
  3616. }
  3617. return;
  3618. }
  3619. // Allocate temporary variable
  3620. asCDataType dt = ctx->type.dataType;
  3621. dt.MakeReference(false);
  3622. dt.MakeReadOnly(false);
  3623. int offset = AllocateVariable(dt, true, forceOnHeap);
  3624. // Objects stored on the stack are not considered references
  3625. dt.MakeReference(IsVariableOnHeap(offset));
  3626. asCTypeInfo lvalue;
  3627. lvalue.Set(dt);
  3628. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  3629. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3630. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  3631. // Push the reference to the temporary variable on the stack
  3632. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3633. ctx->type.Set(dt);
  3634. ctx->type.isTemporary = true;
  3635. ctx->type.stackOffset = (short)offset;
  3636. ctx->type.isVariable = true;
  3637. ctx->type.isExplicitHandle = isExplicitHandle;
  3638. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  3639. }
  3640. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  3641. {
  3642. // Get return type and location
  3643. sVariable *v = variables->GetVariable("return");
  3644. // Basic validations
  3645. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  3646. {
  3647. Error(TXT_MUST_RETURN_VALUE, rnode);
  3648. return;
  3649. }
  3650. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  3651. {
  3652. Error(TXT_CANT_RETURN_VALUE, rnode);
  3653. return;
  3654. }
  3655. // Compile the expression
  3656. if( rnode->firstChild )
  3657. {
  3658. // Compile the expression
  3659. asSExprContext expr(engine);
  3660. int r = CompileAssignment(rnode->firstChild, &expr);
  3661. if( r < 0 ) return;
  3662. if( v->type.IsReference() )
  3663. {
  3664. // The expression that gives the reference must not use any of the
  3665. // variables that must be destroyed upon exit, because then it means
  3666. // reference will stay alive while the clean-up is done, which could
  3667. // potentially mean that the reference is invalidated by the clean-up.
  3668. //
  3669. // When the function is returning a reference, the clean-up of the
  3670. // variables must be done before the evaluation of the expression.
  3671. //
  3672. // A reference to a global variable, or a class member for class methods
  3673. // should be allowed to be returned.
  3674. if( !(expr.type.dataType.IsReference() ||
  3675. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  3676. {
  3677. // Clean up the potential deferred parameters
  3678. ProcessDeferredParams(&expr);
  3679. Error(TXT_NOT_VALID_REFERENCE, rnode);
  3680. return;
  3681. }
  3682. // No references to local variables, temporary variables, or parameters
  3683. // are allowed to be returned, since they go out of scope when the function
  3684. // returns. Even reference parameters are disallowed, since it is not possible
  3685. // to know the scope of them. The exception is the 'this' pointer, which
  3686. // is treated by the compiler as a local variable, but isn't really so.
  3687. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  3688. {
  3689. // Clean up the potential deferred parameters
  3690. ProcessDeferredParams(&expr);
  3691. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  3692. return;
  3693. }
  3694. // The type must match exactly as we cannot convert
  3695. // the reference without loosing the original value
  3696. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  3697. (expr.type.dataType.IsObject() &&
  3698. !expr.type.dataType.IsObjectHandle() &&
  3699. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  3700. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  3701. {
  3702. // Clean up the potential deferred parameters
  3703. ProcessDeferredParams(&expr);
  3704. asCString str;
  3705. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3706. Error(str, rnode);
  3707. return;
  3708. }
  3709. // The expression must not have any deferred expressions, because the evaluation
  3710. // of these cannot be done without keeping the reference which is not safe
  3711. if( expr.deferredParams.GetLength() )
  3712. {
  3713. // Clean up the potential deferred parameters
  3714. ProcessDeferredParams(&expr);
  3715. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  3716. return;
  3717. }
  3718. // Make sure the expression isn't using any local variables that
  3719. // will need to be cleaned up before the function completes
  3720. asCArray<int> usedVars;
  3721. expr.bc.GetVarsUsed(usedVars);
  3722. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  3723. {
  3724. int var = GetVariableSlot(usedVars[n]);
  3725. if( var != -1 )
  3726. {
  3727. asCDataType dt = variableAllocations[var];
  3728. if( dt.IsObject() )
  3729. {
  3730. ProcessDeferredParams(&expr);
  3731. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  3732. return;
  3733. }
  3734. }
  3735. }
  3736. // All objects in the function must be cleaned up before the expression
  3737. // is evaluated, otherwise there is a possibility that the cleanup will
  3738. // invalidate the reference.
  3739. // Destroy the local variables before loading
  3740. // the reference into the register. This will
  3741. // be done before the expression is evaluated.
  3742. DestroyVariables(bc);
  3743. // For primitives the reference is already in the register,
  3744. // but for non-primitives the reference is on the stack so we
  3745. // need to load it into the register
  3746. if( !expr.type.dataType.IsPrimitive() )
  3747. {
  3748. if( !expr.type.dataType.IsObjectHandle() &&
  3749. expr.type.dataType.IsReference() )
  3750. expr.bc.Instr(asBC_RDSPtr);
  3751. expr.bc.Instr(asBC_PopRPtr);
  3752. }
  3753. // There are no temporaries to release so we're done
  3754. }
  3755. else // if( !v->type.IsReference() )
  3756. {
  3757. ProcessPropertyGetAccessor(&expr, rnode);
  3758. // Prepare the value for assignment
  3759. IsVariableInitialized(&expr.type, rnode->firstChild);
  3760. if( v->type.IsPrimitive() )
  3761. {
  3762. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3763. // Implicitly convert the value to the return type
  3764. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3765. // Verify that the conversion was successful
  3766. if( expr.type.dataType != v->type )
  3767. {
  3768. asCString str;
  3769. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3770. Error(str, rnode);
  3771. return;
  3772. }
  3773. else
  3774. {
  3775. ConvertToVariable(&expr);
  3776. // Clean up the local variables and process deferred parameters
  3777. DestroyVariables(&expr.bc);
  3778. ProcessDeferredParams(&expr);
  3779. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3780. // Load the variable in the register
  3781. if( v->type.GetSizeOnStackDWords() == 1 )
  3782. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3783. else
  3784. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  3785. }
  3786. }
  3787. else if( v->type.IsObject() )
  3788. {
  3789. // Value types are returned on the stack, in a location
  3790. // that has been reserved by the calling function.
  3791. if( outFunc->DoesReturnOnStack() )
  3792. {
  3793. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  3794. // it should be called directly instead of first converting the expression and
  3795. // then copy the value.
  3796. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3797. {
  3798. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3799. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3800. {
  3801. asCString str;
  3802. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3803. Error(str, rnode->firstChild);
  3804. return;
  3805. }
  3806. }
  3807. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  3808. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  3809. // Clean up the local variables and process deferred parameters
  3810. DestroyVariables(&expr.bc);
  3811. ProcessDeferredParams(&expr);
  3812. }
  3813. else
  3814. {
  3815. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  3816. // Prepare the expression to be loaded into the object
  3817. // register. This will place the reference in local variable
  3818. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  3819. // Pop the reference to the temporary variable
  3820. expr.bc.Instr(asBC_PopPtr);
  3821. // Clean up the local variables and process deferred parameters
  3822. DestroyVariables(&expr.bc);
  3823. ProcessDeferredParams(&expr);
  3824. // Load the object pointer into the object register
  3825. // LOADOBJ also clears the address in the variable
  3826. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  3827. // LOADOBJ cleared the address in the variable so the object will not be freed
  3828. // here, but the temporary variable must still be freed so the slot can be reused
  3829. // By releasing without the bytecode we do just that.
  3830. ReleaseTemporaryVariable(expr.type, 0);
  3831. }
  3832. }
  3833. }
  3834. expr.bc.OptimizeLocally(tempVariableOffsets);
  3835. bc->AddCode(&expr.bc);
  3836. }
  3837. else
  3838. {
  3839. // For functions that don't return anything
  3840. // we just detroy the local variables
  3841. DestroyVariables(bc);
  3842. }
  3843. // Jump to the end of the function
  3844. bc->InstrINT(asBC_JMP, 0);
  3845. }
  3846. void asCCompiler::DestroyVariables(asCByteCode *bc)
  3847. {
  3848. // Call destructor on all variables except for the function parameters
  3849. // Put the clean-up in a block to allow exception handler to understand this
  3850. bc->Block(true);
  3851. asCVariableScope *vs = variables;
  3852. while( vs )
  3853. {
  3854. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3855. if( vs->variables[n]->stackOffset > 0 )
  3856. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3857. vs = vs->parent;
  3858. }
  3859. bc->Block(false);
  3860. }
  3861. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  3862. {
  3863. variables = asNEW(asCVariableScope)(variables);
  3864. if( variables == 0 )
  3865. {
  3866. // Out of memory
  3867. return;
  3868. }
  3869. variables->isBreakScope = isBreakScope;
  3870. variables->isContinueScope = isContinueScope;
  3871. }
  3872. void asCCompiler::RemoveVariableScope()
  3873. {
  3874. if( variables )
  3875. {
  3876. asCVariableScope *var = variables;
  3877. variables = variables->parent;
  3878. asDELETE(var,asCVariableScope);
  3879. }
  3880. }
  3881. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  3882. {
  3883. asCString str;
  3884. int r = 0, c = 0;
  3885. asASSERT( node );
  3886. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3887. builder->WriteError(script->name, msg, r, c);
  3888. hasCompileErrors = true;
  3889. }
  3890. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  3891. {
  3892. asCString str;
  3893. int r = 0, c = 0;
  3894. asASSERT( node );
  3895. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3896. builder->WriteWarning(script->name, msg, r, c);
  3897. }
  3898. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  3899. {
  3900. asCString str;
  3901. int r = 0, c = 0;
  3902. asASSERT( node );
  3903. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3904. builder->WriteInfo(script->name, msg, r, c, false);
  3905. }
  3906. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  3907. {
  3908. int r = 0, c = 0;
  3909. asASSERT( node );
  3910. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3911. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3912. {
  3913. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  3914. if( inType && func->funcType == asFUNC_VIRTUAL )
  3915. func = inType->virtualFunctionTable[func->vfTableIdx];
  3916. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  3917. }
  3918. }
  3919. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  3920. {
  3921. int l = int(reservedVariables.GetLength());
  3922. ctx->bc.GetVarsUsed(reservedVariables);
  3923. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  3924. reservedVariables.SetLength(l);
  3925. return var;
  3926. }
  3927. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  3928. {
  3929. asCDataType t(type);
  3930. t.MakeReference(false);
  3931. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  3932. t.SetTokenType(ttInt);
  3933. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  3934. t.SetTokenType(ttDouble);
  3935. // Only null handles have the token type unrecognized token
  3936. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  3937. bool isOnHeap = true;
  3938. if( t.IsPrimitive() ||
  3939. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  3940. {
  3941. // Primitives and value types (unless overridden) are allocated on the stack
  3942. isOnHeap = false;
  3943. }
  3944. // Find a free location with the same type
  3945. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  3946. {
  3947. int slot = freeVariables[n];
  3948. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  3949. variableIsTemporary[slot] == isTemporary &&
  3950. variableIsOnHeap[slot] == isOnHeap )
  3951. {
  3952. // We can't return by slot, must count variable sizes
  3953. int offset = GetVariableOffset(slot);
  3954. // Verify that it is not in the list of reserved variables
  3955. bool isUsed = false;
  3956. if( reservedVariables.GetLength() )
  3957. isUsed = reservedVariables.Exists(offset);
  3958. if( !isUsed )
  3959. {
  3960. if( n != freeVariables.GetLength() - 1 )
  3961. freeVariables[n] = freeVariables.PopLast();
  3962. else
  3963. freeVariables.PopLast();
  3964. if( isTemporary )
  3965. tempVariables.PushLast(offset);
  3966. return offset;
  3967. }
  3968. }
  3969. }
  3970. variableAllocations.PushLast(t);
  3971. variableIsTemporary.PushLast(isTemporary);
  3972. variableIsOnHeap.PushLast(isOnHeap);
  3973. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  3974. if( isTemporary )
  3975. {
  3976. // Add offset to the currently allocated temporary variables
  3977. tempVariables.PushLast(offset);
  3978. // Add offset to all known offsets to temporary variables, whether allocated or not
  3979. tempVariableOffsets.PushLast(offset);
  3980. }
  3981. return offset;
  3982. }
  3983. int asCCompiler::GetVariableOffset(int varIndex)
  3984. {
  3985. // Return offset to the last dword on the stack
  3986. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  3987. int varOffset = 1;
  3988. // Skip lower variables
  3989. for( int n = 0; n < varIndex; n++ )
  3990. {
  3991. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3992. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  3993. else
  3994. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  3995. }
  3996. if( varIndex < (int)variableAllocations.GetLength() )
  3997. {
  3998. // For variables larger than 1 dword the returned offset should be to the last dword
  3999. int size;
  4000. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4001. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4002. else
  4003. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4004. if( size > 1 )
  4005. varOffset += size-1;
  4006. }
  4007. return varOffset;
  4008. }
  4009. int asCCompiler::GetVariableSlot(int offset)
  4010. {
  4011. int varOffset = 1;
  4012. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4013. {
  4014. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4015. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4016. else
  4017. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4018. if( varOffset == offset )
  4019. return n;
  4020. varOffset++;
  4021. }
  4022. return -1;
  4023. }
  4024. bool asCCompiler::IsVariableOnHeap(int offset)
  4025. {
  4026. int varSlot = GetVariableSlot(offset);
  4027. if( varSlot < 0 )
  4028. {
  4029. // This happens for function arguments that are considered as on the heap
  4030. return true;
  4031. }
  4032. return variableIsOnHeap[varSlot];
  4033. }
  4034. void asCCompiler::DeallocateVariable(int offset)
  4035. {
  4036. // Remove temporary variable
  4037. int n;
  4038. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4039. {
  4040. if( offset == tempVariables[n] )
  4041. {
  4042. if( n == (int)tempVariables.GetLength()-1 )
  4043. tempVariables.PopLast();
  4044. else
  4045. tempVariables[n] = tempVariables.PopLast();
  4046. break;
  4047. }
  4048. }
  4049. n = GetVariableSlot(offset);
  4050. if( n != -1 )
  4051. {
  4052. freeVariables.PushLast(n);
  4053. return;
  4054. }
  4055. // We might get here if the variable was implicitly declared
  4056. // because it was use before a formal declaration, in this case
  4057. // the offset is 0x7FFF
  4058. asASSERT(offset == 0x7FFF);
  4059. }
  4060. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  4061. {
  4062. if( t.isTemporary )
  4063. {
  4064. ReleaseTemporaryVariable(t.stackOffset, bc);
  4065. t.isTemporary = false;
  4066. }
  4067. }
  4068. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4069. {
  4070. asASSERT( tempVariables.Exists(offset) );
  4071. if( bc )
  4072. {
  4073. // We need to call the destructor on the true variable type
  4074. int n = GetVariableSlot(offset);
  4075. asASSERT( n >= 0 );
  4076. if( n >= 0 )
  4077. {
  4078. asCDataType dt = variableAllocations[n];
  4079. bool isOnHeap = variableIsOnHeap[n];
  4080. // Call destructor
  4081. CallDestructor(dt, offset, isOnHeap, bc);
  4082. }
  4083. }
  4084. DeallocateVariable(offset);
  4085. }
  4086. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  4087. {
  4088. if( ctx->type.dataType.IsReference() )
  4089. {
  4090. if( ctx->type.dataType.IsObject() )
  4091. {
  4092. ctx->type.dataType.MakeReference(false);
  4093. if( generateCode )
  4094. ctx->bc.Instr(asBC_RDSPtr);
  4095. }
  4096. else
  4097. {
  4098. // This should never happen as primitives are treated differently
  4099. asASSERT(false);
  4100. }
  4101. }
  4102. }
  4103. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  4104. {
  4105. // No need to check if there is no variable scope
  4106. if( variables == 0 ) return true;
  4107. // Temporary variables are assumed to be initialized
  4108. if( type->isTemporary ) return true;
  4109. // Verify that it is a variable
  4110. if( !type->isVariable ) return true;
  4111. // Find the variable
  4112. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4113. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4114. if( v == 0 ) return true;
  4115. if( v->isInitialized ) return true;
  4116. // Complex types don't need this test
  4117. if( v->type.IsObject() ) return true;
  4118. // Mark as initialized so that the user will not be bothered again
  4119. v->isInitialized = true;
  4120. // Write warning
  4121. asCString str;
  4122. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4123. Warning(str, node);
  4124. return false;
  4125. }
  4126. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  4127. {
  4128. // Check if the variable is initialized (if it indeed is a variable)
  4129. IsVariableInitialized(&ctx->type, node);
  4130. asCDataType to = ctx->type.dataType;
  4131. to.MakeReference(false);
  4132. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4133. ProcessDeferredParams(ctx);
  4134. }
  4135. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  4136. {
  4137. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4138. int l = int(reservedVariables.GetLength());
  4139. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4140. ProcessPropertyGetAccessor(rctx, node);
  4141. // Make sure the rvalue is initialized if it is a variable
  4142. IsVariableInitialized(&rctx->type, node);
  4143. if( lvalue->IsPrimitive() )
  4144. {
  4145. if( rctx->type.dataType.IsPrimitive() )
  4146. {
  4147. if( rctx->type.dataType.IsReference() )
  4148. {
  4149. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4150. ConvertToVariableNotIn(rctx, lvalueExpr);
  4151. }
  4152. }
  4153. // Implicitly convert the value to the right type
  4154. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4155. // Check data type
  4156. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4157. {
  4158. asCString str;
  4159. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  4160. Error(str, node);
  4161. rctx->type.SetDummy();
  4162. }
  4163. // Make sure the rvalue is a variable
  4164. if( !rctx->type.isVariable )
  4165. ConvertToVariableNotIn(rctx, lvalueExpr);
  4166. }
  4167. else
  4168. {
  4169. asCDataType to = *lvalue;
  4170. to.MakeReference(false);
  4171. // TODO: ImplicitConversion should know to do this by itself
  4172. // First convert to a handle which will do a reference cast
  4173. if( !lvalue->IsObjectHandle() &&
  4174. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4175. to.MakeHandle(true);
  4176. // Don't allow the implicit conversion to create an object
  4177. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4178. if( !lvalue->IsObjectHandle() &&
  4179. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  4180. {
  4181. // Then convert to a reference, which will validate the handle
  4182. to.MakeHandle(false);
  4183. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4184. }
  4185. // Check data type
  4186. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4187. {
  4188. asCString str;
  4189. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  4190. Error(str, node);
  4191. }
  4192. else
  4193. {
  4194. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4195. if( lvalue->IsObject() )
  4196. asASSERT(!rctx->type.dataType.IsReference());
  4197. }
  4198. }
  4199. // Unreserve variables
  4200. reservedVariables.SetLength(l);
  4201. }
  4202. bool asCCompiler::IsLValue(asCTypeInfo &type)
  4203. {
  4204. if( !type.isLValue ) return false;
  4205. if( type.dataType.IsReadOnly() ) return false;
  4206. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4207. return true;
  4208. }
  4209. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  4210. {
  4211. if( lvalue->dataType.IsReadOnly() )
  4212. {
  4213. Error(TXT_REF_IS_READ_ONLY, node);
  4214. return -1;
  4215. }
  4216. if( lvalue->dataType.IsPrimitive() )
  4217. {
  4218. if( lvalue->isVariable )
  4219. {
  4220. // Copy the value between the variables directly
  4221. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4222. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4223. else
  4224. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4225. // Mark variable as initialized
  4226. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4227. if( v ) v->isInitialized = true;
  4228. }
  4229. else if( lvalue->dataType.IsReference() )
  4230. {
  4231. // Copy the value of the variable to the reference in the register
  4232. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4233. if( s == 1 )
  4234. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4235. else if( s == 2 )
  4236. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4237. else if( s == 4 )
  4238. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4239. else if( s == 8 )
  4240. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4241. }
  4242. else
  4243. {
  4244. Error(TXT_NOT_VALID_LVALUE, node);
  4245. return -1;
  4246. }
  4247. }
  4248. else if( !lvalue->isExplicitHandle )
  4249. {
  4250. asSExprContext ctx(engine);
  4251. ctx.type = *lvalue;
  4252. Dereference(&ctx, true);
  4253. *lvalue = ctx.type;
  4254. bc->AddCode(&ctx.bc);
  4255. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4256. if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4257. {
  4258. asSExprContext res(engine);
  4259. PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType());
  4260. bc->AddCode(&res.bc);
  4261. *lvalue = res.type;
  4262. }
  4263. else if( beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4264. {
  4265. // Call the default copy operator for script classes
  4266. // This is done differently because the default copy operator
  4267. // is registered as returning int&, but in reality it returns
  4268. // a reference to the object.
  4269. // TODO: Avoid this special case by implementing a copystub for
  4270. // script classes that uses the default copy operator
  4271. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4272. bc->Instr(asBC_PshRPtr);
  4273. }
  4274. else
  4275. {
  4276. // Default copy operator
  4277. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4278. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  4279. {
  4280. asCString msg;
  4281. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  4282. Error(msg, node);
  4283. return -1;
  4284. }
  4285. // Copy larger data types from a reference
  4286. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4287. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4288. }
  4289. }
  4290. else
  4291. {
  4292. // TODO: The object handle can be stored in a variable as well
  4293. if( !lvalue->dataType.IsReference() )
  4294. {
  4295. Error(TXT_NOT_VALID_REFERENCE, node);
  4296. return -1;
  4297. }
  4298. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  4299. // Mark variable as initialized
  4300. if( variables )
  4301. {
  4302. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4303. if( v ) v->isInitialized = true;
  4304. }
  4305. }
  4306. return 0;
  4307. }
  4308. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4309. {
  4310. bool conversionDone = false;
  4311. asCArray<int> ops;
  4312. asUINT n;
  4313. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  4314. {
  4315. // We need it to be a reference
  4316. if( !ctx->type.dataType.IsReference() )
  4317. {
  4318. asCDataType to = ctx->type.dataType;
  4319. to.MakeReference(true);
  4320. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  4321. }
  4322. if( isExplicit )
  4323. {
  4324. // Allow dynamic cast between object handles (only for script objects).
  4325. // At run time this may result in a null handle,
  4326. // which when used will throw an exception
  4327. conversionDone = true;
  4328. if( generateCode )
  4329. {
  4330. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  4331. // Allocate a temporary variable for the returned object
  4332. int returnOffset = AllocateVariable(to, true);
  4333. // Move the pointer from the object register to the temporary variable
  4334. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  4335. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  4336. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4337. ctx->type.SetVariable(to, returnOffset, true);
  4338. ctx->type.dataType.MakeReference(true);
  4339. }
  4340. else
  4341. {
  4342. ctx->type.dataType = to;
  4343. ctx->type.dataType.MakeReference(true);
  4344. }
  4345. }
  4346. else
  4347. {
  4348. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4349. {
  4350. conversionDone = true;
  4351. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4352. }
  4353. }
  4354. }
  4355. else
  4356. {
  4357. // Find a suitable registered behaviour
  4358. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  4359. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  4360. {
  4361. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  4362. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  4363. {
  4364. int funcId = beh->operators[n+1];
  4365. // Is the operator for the output type?
  4366. asCScriptFunction *func = engine->scriptFunctions[funcId];
  4367. if( func->returnType.GetObjectType() != to.GetObjectType() )
  4368. continue;
  4369. ops.PushLast(funcId);
  4370. }
  4371. }
  4372. // It shouldn't be possible to have more than one
  4373. asASSERT( ops.GetLength() <= 1 );
  4374. // Should only have one behaviour for each output type
  4375. if( ops.GetLength() == 1 )
  4376. {
  4377. if( generateCode )
  4378. {
  4379. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4380. // null, we can create a special CALLSYS instruction that checks
  4381. // if the object pointer is null and if so sets the object register
  4382. // to null directly without executing the function.
  4383. //
  4384. // Alternatively I could force the ref cast behaviours be global
  4385. // functions with 1 parameter, even though they should still be
  4386. // registered with RegisterObjectBehaviour()
  4387. // Add code to avoid calling the cast behaviour if the handle is already null,
  4388. // because that will raise a null pointer exception due to the cast behaviour
  4389. // being a class method, and the this pointer cannot be null.
  4390. if( !ctx->type.isVariable )
  4391. {
  4392. Dereference(ctx, true);
  4393. ConvertToVariable(ctx);
  4394. }
  4395. // The reference on the stack will not be used
  4396. ctx->bc.Instr(asBC_PopPtr);
  4397. // TODO: runtime optimize: should have immediate comparison for null pointer
  4398. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4399. // 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)
  4400. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4401. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4402. DeallocateVariable(offset);
  4403. int afterLabel = nextLabel++;
  4404. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4405. // Call the cast operator
  4406. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4407. ctx->bc.Instr(asBC_RDSPtr);
  4408. ctx->type.dataType.MakeReference(false);
  4409. asCArray<asSExprContext *> args;
  4410. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4411. ctx->bc.Instr(asBC_PopPtr);
  4412. int endLabel = nextLabel++;
  4413. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4414. ctx->bc.Label((short)afterLabel);
  4415. // Make a NULL pointer
  4416. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4417. ctx->bc.Label((short)endLabel);
  4418. // Push the reference to the handle on the stack
  4419. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4420. }
  4421. else
  4422. {
  4423. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4424. ctx->type.Set(func->returnType);
  4425. }
  4426. }
  4427. else if( ops.GetLength() == 0 )
  4428. {
  4429. // Check for the generic ref cast behaviour
  4430. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  4431. {
  4432. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  4433. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  4434. {
  4435. int funcId = beh->operators[n+1];
  4436. // Does the operator take the ?&out parameter?
  4437. asCScriptFunction *func = engine->scriptFunctions[funcId];
  4438. if( func->parameterTypes.GetLength() != 1 ||
  4439. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4440. func->inOutFlags[0] != asTM_OUTREF )
  4441. continue;
  4442. ops.PushLast(funcId);
  4443. }
  4444. }
  4445. // It shouldn't be possible to have more than one
  4446. asASSERT( ops.GetLength() <= 1 );
  4447. if( ops.GetLength() == 1 )
  4448. {
  4449. if( generateCode )
  4450. {
  4451. asASSERT(to.IsObjectHandle());
  4452. // Allocate a temporary variable of the requested handle type
  4453. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  4454. // Pass the reference of that variable to the function as output parameter
  4455. asCDataType toRef(to);
  4456. toRef.MakeReference(true);
  4457. asCArray<asSExprContext *> args;
  4458. asSExprContext arg(engine);
  4459. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4460. // Don't mark the variable as temporary, so it won't be freed too early
  4461. arg.type.SetVariable(toRef, stackOffset, false);
  4462. arg.type.isLValue = true;
  4463. arg.type.isExplicitHandle = true;
  4464. args.PushLast(&arg);
  4465. // Call the behaviour method
  4466. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4467. // Use the reference to the variable as the result of the expression
  4468. // Now we can mark the variable as temporary
  4469. ctx->type.SetVariable(toRef, stackOffset, true);
  4470. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4471. }
  4472. else
  4473. {
  4474. // All casts are legal
  4475. ctx->type.Set(to);
  4476. }
  4477. }
  4478. }
  4479. }
  4480. return conversionDone;
  4481. }
  4482. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4483. {
  4484. asCDataType to = toOrig;
  4485. to.MakeReference(false);
  4486. asASSERT( !ctx->type.dataType.IsReference() );
  4487. // Maybe no conversion is needed
  4488. if( to.IsEqualExceptConst(ctx->type.dataType) )
  4489. {
  4490. // A primitive is const or not
  4491. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4492. return asCC_NO_CONV;
  4493. }
  4494. // Is the conversion an ambiguous enum value?
  4495. if( ctx->enumValue != "" )
  4496. {
  4497. if( to.IsEnumType() )
  4498. {
  4499. // Attempt to resolve an ambiguous enum value
  4500. asCDataType out;
  4501. asDWORD value;
  4502. if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) )
  4503. {
  4504. ctx->type.SetConstantDW(out, value);
  4505. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4506. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  4507. return asCC_NO_CONV;
  4508. }
  4509. }
  4510. // The enum value is ambiguous
  4511. if( node && generateCode )
  4512. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  4513. // Set a dummy to allow the compiler to try to continue the conversion
  4514. ctx->type.SetDummy();
  4515. }
  4516. // Determine the cost of this conversion
  4517. asUINT cost = asCC_NO_CONV;
  4518. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4519. cost = asCC_INT_FLOAT_CONV;
  4520. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
  4521. cost = asCC_INT_FLOAT_CONV;
  4522. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  4523. cost = asCC_SIGNED_CONV;
  4524. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  4525. cost = asCC_SIGNED_CONV;
  4526. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  4527. cost = asCC_PRIMITIVE_SIZE_CONV;
  4528. // Start by implicitly converting constant values
  4529. if( ctx->type.isConstant )
  4530. {
  4531. ImplicitConversionConstant(ctx, to, node, convType);
  4532. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4533. return cost;
  4534. }
  4535. // Allow implicit conversion between numbers
  4536. if( generateCode )
  4537. {
  4538. // When generating the code the decision has already been made, so we don't bother determining the cost
  4539. // Convert smaller types to 32bit first
  4540. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  4541. if( s < 4 )
  4542. {
  4543. ConvertToTempVariable(ctx);
  4544. if( ctx->type.dataType.IsIntegerType() )
  4545. {
  4546. if( s == 1 )
  4547. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  4548. else if( s == 2 )
  4549. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  4550. ctx->type.dataType.SetTokenType(ttInt);
  4551. }
  4552. else if( ctx->type.dataType.IsUnsignedType() )
  4553. {
  4554. if( s == 1 )
  4555. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  4556. else if( s == 2 )
  4557. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  4558. ctx->type.dataType.SetTokenType(ttUInt);
  4559. }
  4560. }
  4561. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  4562. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4563. {
  4564. if( ctx->type.dataType.IsIntegerType() ||
  4565. ctx->type.dataType.IsUnsignedType() )
  4566. {
  4567. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4568. {
  4569. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4570. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4571. }
  4572. else
  4573. {
  4574. ConvertToTempVariable(ctx);
  4575. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4576. int offset = AllocateVariable(to, true);
  4577. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4578. ctx->type.SetVariable(to, offset, true);
  4579. }
  4580. }
  4581. else if( ctx->type.dataType.IsFloatType() )
  4582. {
  4583. ConvertToTempVariable(ctx);
  4584. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  4585. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4586. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4587. if( convType != asIC_EXPLICIT_VAL_CAST )
  4588. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4589. }
  4590. else if( ctx->type.dataType.IsDoubleType() )
  4591. {
  4592. ConvertToTempVariable(ctx);
  4593. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4594. int offset = AllocateVariable(to, true);
  4595. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  4596. ctx->type.SetVariable(to, offset, true);
  4597. if( convType != asIC_EXPLICIT_VAL_CAST )
  4598. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4599. }
  4600. // Convert to smaller integer if necessary
  4601. int s = to.GetSizeInMemoryBytes();
  4602. if( s < 4 )
  4603. {
  4604. ConvertToTempVariable(ctx);
  4605. if( s == 1 )
  4606. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4607. else if( s == 2 )
  4608. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4609. }
  4610. }
  4611. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4612. {
  4613. if( ctx->type.dataType.IsIntegerType() ||
  4614. ctx->type.dataType.IsUnsignedType() )
  4615. {
  4616. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4617. {
  4618. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4619. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4620. }
  4621. else
  4622. {
  4623. ConvertToTempVariable(ctx);
  4624. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4625. int offset = AllocateVariable(to, true);
  4626. if( ctx->type.dataType.IsUnsignedType() )
  4627. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4628. else
  4629. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4630. ctx->type.SetVariable(to, offset, true);
  4631. }
  4632. }
  4633. else if( ctx->type.dataType.IsFloatType() )
  4634. {
  4635. ConvertToTempVariable(ctx);
  4636. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4637. int offset = AllocateVariable(to, true);
  4638. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  4639. ctx->type.SetVariable(to, offset, true);
  4640. if( convType != asIC_EXPLICIT_VAL_CAST )
  4641. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4642. }
  4643. else if( ctx->type.dataType.IsDoubleType() )
  4644. {
  4645. ConvertToTempVariable(ctx);
  4646. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  4647. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4648. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4649. if( convType != asIC_EXPLICIT_VAL_CAST )
  4650. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4651. }
  4652. }
  4653. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4654. {
  4655. if( ctx->type.dataType.IsIntegerType() ||
  4656. ctx->type.dataType.IsUnsignedType() )
  4657. {
  4658. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4659. {
  4660. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4661. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4662. }
  4663. else
  4664. {
  4665. ConvertToTempVariable(ctx);
  4666. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4667. int offset = AllocateVariable(to, true);
  4668. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4669. ctx->type.SetVariable(to, offset, true);
  4670. }
  4671. }
  4672. else if( ctx->type.dataType.IsFloatType() )
  4673. {
  4674. ConvertToTempVariable(ctx);
  4675. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  4676. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4677. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4678. if( convType != asIC_EXPLICIT_VAL_CAST )
  4679. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4680. }
  4681. else if( ctx->type.dataType.IsDoubleType() )
  4682. {
  4683. ConvertToTempVariable(ctx);
  4684. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4685. int offset = AllocateVariable(to, true);
  4686. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  4687. ctx->type.SetVariable(to, offset, true);
  4688. if( convType != asIC_EXPLICIT_VAL_CAST )
  4689. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4690. }
  4691. // Convert to smaller integer if necessary
  4692. int s = to.GetSizeInMemoryBytes();
  4693. if( s < 4 )
  4694. {
  4695. ConvertToTempVariable(ctx);
  4696. if( s == 1 )
  4697. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4698. else if( s == 2 )
  4699. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4700. }
  4701. }
  4702. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4703. {
  4704. if( ctx->type.dataType.IsIntegerType() ||
  4705. ctx->type.dataType.IsUnsignedType() )
  4706. {
  4707. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4708. {
  4709. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4710. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4711. }
  4712. else
  4713. {
  4714. ConvertToTempVariable(ctx);
  4715. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4716. int offset = AllocateVariable(to, true);
  4717. if( ctx->type.dataType.IsUnsignedType() )
  4718. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4719. else
  4720. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4721. ctx->type.SetVariable(to, offset, true);
  4722. }
  4723. }
  4724. else if( ctx->type.dataType.IsFloatType() )
  4725. {
  4726. ConvertToTempVariable(ctx);
  4727. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4728. int offset = AllocateVariable(to, true);
  4729. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  4730. ctx->type.SetVariable(to, offset, true);
  4731. if( convType != asIC_EXPLICIT_VAL_CAST )
  4732. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4733. }
  4734. else if( ctx->type.dataType.IsDoubleType() )
  4735. {
  4736. ConvertToTempVariable(ctx);
  4737. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  4738. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4739. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4740. if( convType != asIC_EXPLICIT_VAL_CAST )
  4741. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4742. }
  4743. }
  4744. else if( to.IsFloatType() )
  4745. {
  4746. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4747. {
  4748. ConvertToTempVariable(ctx);
  4749. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  4750. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4751. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4752. }
  4753. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4754. {
  4755. ConvertToTempVariable(ctx);
  4756. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4757. int offset = AllocateVariable(to, true);
  4758. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  4759. ctx->type.SetVariable(to, offset, true);
  4760. }
  4761. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4762. {
  4763. ConvertToTempVariable(ctx);
  4764. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  4765. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4766. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4767. }
  4768. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4769. {
  4770. ConvertToTempVariable(ctx);
  4771. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4772. int offset = AllocateVariable(to, true);
  4773. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  4774. ctx->type.SetVariable(to, offset, true);
  4775. }
  4776. else if( ctx->type.dataType.IsDoubleType() )
  4777. {
  4778. ConvertToTempVariable(ctx);
  4779. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4780. int offset = AllocateVariable(to, true);
  4781. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  4782. ctx->type.SetVariable(to, offset, true);
  4783. }
  4784. }
  4785. else if( to.IsDoubleType() )
  4786. {
  4787. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4788. {
  4789. ConvertToTempVariable(ctx);
  4790. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4791. int offset = AllocateVariable(to, true);
  4792. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  4793. ctx->type.SetVariable(to, offset, true);
  4794. }
  4795. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4796. {
  4797. ConvertToTempVariable(ctx);
  4798. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  4799. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4800. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4801. }
  4802. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4803. {
  4804. ConvertToTempVariable(ctx);
  4805. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4806. int offset = AllocateVariable(to, true);
  4807. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  4808. ctx->type.SetVariable(to, offset, true);
  4809. }
  4810. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4811. {
  4812. ConvertToTempVariable(ctx);
  4813. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  4814. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4815. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4816. }
  4817. else if( ctx->type.dataType.IsFloatType() )
  4818. {
  4819. ConvertToTempVariable(ctx);
  4820. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4821. int offset = AllocateVariable(to, true);
  4822. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  4823. ctx->type.SetVariable(to, offset, true);
  4824. }
  4825. }
  4826. }
  4827. else
  4828. {
  4829. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  4830. to.IsFloatType() || to.IsDoubleType() ||
  4831. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  4832. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  4833. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4834. {
  4835. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4836. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4837. }
  4838. }
  4839. // Primitive types on the stack, can be const or non-const
  4840. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4841. return cost;
  4842. }
  4843. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4844. {
  4845. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  4846. ctx->type.dataType.IsNullHandle() );
  4847. // No conversion from void to any other type
  4848. if( ctx->type.dataType.GetTokenType() == ttVoid )
  4849. return asCC_NO_CONV;
  4850. // Do we want a var type?
  4851. if( to.GetTokenType() == ttQuestion )
  4852. {
  4853. // Any type can be converted to a var type, but only when not generating code
  4854. asASSERT( !generateCode );
  4855. ctx->type.dataType = to;
  4856. return asCC_VARIABLE_CONV;
  4857. }
  4858. // Do we want a primitive?
  4859. else if( to.IsPrimitive() )
  4860. {
  4861. if( !ctx->type.dataType.IsPrimitive() )
  4862. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  4863. else
  4864. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  4865. }
  4866. else // The target is a complex type
  4867. {
  4868. if( ctx->type.dataType.IsPrimitive() )
  4869. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4870. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  4871. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4872. }
  4873. return asCC_NO_CONV;
  4874. }
  4875. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4876. {
  4877. if( ctx->type.isExplicitHandle )
  4878. {
  4879. // An explicit handle cannot be converted to a primitive
  4880. if( convType != asIC_IMPLICIT_CONV && node )
  4881. {
  4882. asCString str;
  4883. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4884. Error(str, node);
  4885. }
  4886. return asCC_NO_CONV;
  4887. }
  4888. // TODO: Must use the const cast behaviour if the object is read-only
  4889. // Find matching value cast behaviours
  4890. // Here we're only interested in those that convert the type to a primitive type
  4891. asCArray<int> funcs;
  4892. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4893. if( beh == 0 )
  4894. {
  4895. if( convType != asIC_IMPLICIT_CONV && node )
  4896. {
  4897. asCString str;
  4898. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4899. Error(str, node);
  4900. }
  4901. return asCC_NO_CONV;
  4902. }
  4903. if( convType == asIC_EXPLICIT_VAL_CAST )
  4904. {
  4905. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4906. {
  4907. // accept both implicit and explicit cast
  4908. // TODO: 2.29.0: look for opConv or opImplConv methods
  4909. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4910. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4911. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4912. funcs.PushLast(beh->operators[n+1]);
  4913. }
  4914. }
  4915. else
  4916. {
  4917. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4918. {
  4919. // accept only implicit cast
  4920. // TODO: 2.29.0: look for opImplConv methods
  4921. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4922. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4923. funcs.PushLast(beh->operators[n+1]);
  4924. }
  4925. }
  4926. // This matrix describes the priorities of the types to search for, for each target type
  4927. // The first column is the target type, the priorities goes from left to right
  4928. eTokenType matchMtx[10][10] =
  4929. {
  4930. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4931. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4932. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4933. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4934. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4935. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4936. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  4937. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  4938. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  4939. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  4940. };
  4941. // Which row to use?
  4942. eTokenType *row = 0;
  4943. for( unsigned int type = 0; type < 10; type++ )
  4944. {
  4945. if( to.GetTokenType() == matchMtx[type][0] )
  4946. {
  4947. row = &matchMtx[type][0];
  4948. break;
  4949. }
  4950. }
  4951. // Find the best matching cast operator
  4952. int funcId = 0;
  4953. if( row )
  4954. {
  4955. asCDataType target(to);
  4956. // Priority goes from left to right in the matrix
  4957. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  4958. {
  4959. target.SetTokenType(row[attempt]);
  4960. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4961. {
  4962. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  4963. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  4964. {
  4965. funcId = funcs[n];
  4966. break;
  4967. }
  4968. }
  4969. }
  4970. }
  4971. // Did we find a suitable function?
  4972. if( funcId != 0 )
  4973. {
  4974. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  4975. if( generateCode )
  4976. {
  4977. Dereference(ctx, true);
  4978. PerformFunctionCall(funcId, ctx);
  4979. }
  4980. else
  4981. ctx->type.Set(descr->returnType);
  4982. // Allow one more implicit conversion to another primitive type
  4983. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  4984. }
  4985. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  4986. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  4987. funcs.SetLength(0);
  4988. for( asUINT n = 0; n < beh->operators.GetLength(); n+= 2 )
  4989. {
  4990. if( ((convType == asIC_EXPLICIT_VAL_CAST) && asBEHAVE_VALUE_CAST == beh->operators[n]) ||
  4991. asBEHAVE_IMPLICIT_VALUE_CAST == beh->operators[n] )
  4992. {
  4993. int funcId = beh->operators[n+1];
  4994. // Does the operator take the ?&out parameter?
  4995. asCScriptFunction *func = engine->scriptFunctions[funcId];
  4996. if( func->parameterTypes.GetLength() != 1 ||
  4997. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4998. func->inOutFlags[0] != asTM_OUTREF )
  4999. continue;
  5000. funcs.PushLast(funcId);
  5001. }
  5002. }
  5003. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5004. asASSERT( funcs.GetLength() <= 1 );
  5005. if( funcs.GetLength() == 1 )
  5006. {
  5007. if( generateCode )
  5008. {
  5009. // Allocate a temporary variable of the requested type
  5010. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5011. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5012. // Pass the reference of that variable to the function as output parameter
  5013. asCDataType toRef(to);
  5014. toRef.MakeReference(true);
  5015. toRef.MakeReadOnly(false);
  5016. asCArray<asSExprContext *> args;
  5017. asSExprContext arg(engine);
  5018. // Don't mark the variable as temporary, so it won't be freed too early
  5019. arg.type.SetVariable(toRef, stackOffset, false);
  5020. arg.type.isLValue = true;
  5021. arg.exprNode = node;
  5022. args.PushLast(&arg);
  5023. // Call the behaviour method
  5024. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  5025. // Use the reference to the variable as the result of the expression
  5026. // Now we can mark the variable as temporary
  5027. toRef.MakeReference(false);
  5028. ctx->type.SetVariable(toRef, stackOffset, true);
  5029. }
  5030. else
  5031. ctx->type.Set(to);
  5032. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5033. }
  5034. if( convType != asIC_IMPLICIT_CONV && node )
  5035. {
  5036. asCString str;
  5037. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  5038. Error(str, node);
  5039. }
  5040. return asCC_NO_CONV;
  5041. }
  5042. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5043. {
  5044. // Convert null to any object type handle, but not to a non-handle type
  5045. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5046. {
  5047. if( to.IsObjectHandle() )
  5048. {
  5049. ctx->type.dataType = to;
  5050. return asCC_REF_CONV;
  5051. }
  5052. return asCC_NO_CONV;
  5053. }
  5054. asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
  5055. // First attempt to convert the base type without instantiating another instance
  5056. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
  5057. {
  5058. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5059. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  5060. {
  5061. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5062. return asCC_REF_CONV;
  5063. }
  5064. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5065. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  5066. {
  5067. ctx->type.dataType.SetObjectType(to.GetObjectType());
  5068. return asCC_REF_CONV;
  5069. }
  5070. // If the types are not equal yet, then we may still be able to find a reference cast
  5071. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  5072. {
  5073. // A ref cast must not remove the constness
  5074. bool isConst = ctx->type.dataType.IsObjectConst();
  5075. // We may still be able to find an implicit ref cast behaviour
  5076. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5077. ctx->type.dataType.MakeHandleToConst(isConst);
  5078. // Was the conversion done?
  5079. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  5080. return asCC_REF_CONV;
  5081. }
  5082. }
  5083. // Convert matching function types
  5084. if( to.GetFuncDef() )
  5085. {
  5086. // If the input expression is already a funcdef, check if it can be converted
  5087. if( ctx->type.dataType.GetFuncDef() &&
  5088. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  5089. {
  5090. asCScriptFunction *toFunc = to.GetFuncDef();
  5091. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  5092. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5093. {
  5094. ctx->type.dataType.SetFuncDef(toFunc);
  5095. return asCC_REF_CONV;
  5096. }
  5097. }
  5098. // If the input expression is a deferred function ref, check if there is a matching func
  5099. if( ctx->methodName != "" )
  5100. {
  5101. // Determine the namespace
  5102. asSNameSpace *ns = 0;
  5103. asCString name = "";
  5104. int pos = ctx->methodName.FindLast("::");
  5105. if( pos >= 0 )
  5106. {
  5107. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5108. // Trim off the last ::
  5109. if( nsName.GetLength() > 2 )
  5110. nsName.SetLength(nsName.GetLength()-2);
  5111. ns = DetermineNameSpace(nsName);
  5112. name = ctx->methodName.SubString(pos+2);
  5113. }
  5114. else
  5115. {
  5116. DetermineNameSpace("");
  5117. name = ctx->methodName;
  5118. }
  5119. asCArray<int> funcs;
  5120. if( ns )
  5121. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5122. // Check if any of the functions have perfect match
  5123. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5124. {
  5125. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5126. if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
  5127. {
  5128. if( generateCode )
  5129. {
  5130. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5131. // Make sure the identified function is shared if we're compiling a shared function
  5132. if( !func->IsShared() && outFunc->IsShared() )
  5133. {
  5134. asCString msg;
  5135. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5136. Error(msg, node);
  5137. }
  5138. }
  5139. ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
  5140. return asCC_REF_CONV;
  5141. }
  5142. }
  5143. }
  5144. }
  5145. return asCC_NO_CONV;
  5146. }
  5147. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5148. {
  5149. asUINT cost = asCC_NO_CONV;
  5150. // If the base type is still different, and we are allowed to instance
  5151. // another object then we can try an implicit value cast
  5152. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  5153. {
  5154. // TODO: Implement support for implicit constructor/factory
  5155. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  5156. if( beh == 0 )
  5157. return cost;
  5158. asCArray<int> funcs;
  5159. if( convType == asIC_EXPLICIT_VAL_CAST )
  5160. {
  5161. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  5162. {
  5163. // accept both implicit and explicit cast
  5164. // TODO: 2.29.0: Look for opConv and opImplConv methods instead
  5165. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  5166. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  5167. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  5168. funcs.PushLast(beh->operators[n+1]);
  5169. }
  5170. }
  5171. else
  5172. {
  5173. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  5174. {
  5175. // accept only implicit cast
  5176. // TODO: 2.29.0: Look for opImplConv methods instead
  5177. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  5178. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  5179. funcs.PushLast(beh->operators[n+1]);
  5180. }
  5181. }
  5182. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5183. asASSERT( funcs.GetLength() <= 1 );
  5184. if( funcs.GetLength() == 1 )
  5185. {
  5186. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5187. if( generateCode )
  5188. {
  5189. Dereference(ctx, true);
  5190. bool useVariable = false;
  5191. int stackOffset = 0;
  5192. if( f->DoesReturnOnStack() )
  5193. {
  5194. useVariable = true;
  5195. stackOffset = AllocateVariable(f->returnType, true);
  5196. // Push the pointer to the pre-allocated space for the return value
  5197. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5198. // The object pointer is already on the stack, but should be the top
  5199. // one, so we need to swap the pointers in order to get the correct
  5200. ctx->bc.Instr(asBC_SwapPtr);
  5201. }
  5202. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5203. }
  5204. else
  5205. ctx->type.Set(f->returnType);
  5206. cost = asCC_TO_OBJECT_CONV;
  5207. }
  5208. else
  5209. {
  5210. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5211. // Look for a value cast with variable type
  5212. for( asUINT n = 0; n < beh->operators.GetLength(); n+= 2 )
  5213. {
  5214. if( ((convType == asIC_EXPLICIT_VAL_CAST) && asBEHAVE_VALUE_CAST == beh->operators[n]) ||
  5215. asBEHAVE_IMPLICIT_VALUE_CAST == beh->operators[n] )
  5216. {
  5217. int funcId = beh->operators[n+1];
  5218. // Does the operator take the ?&out parameter?
  5219. asCScriptFunction *func = engine->scriptFunctions[funcId];
  5220. if( func->parameterTypes.GetLength() != 1 ||
  5221. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5222. func->inOutFlags[0] != asTM_OUTREF )
  5223. continue;
  5224. funcs.PushLast(funcId);
  5225. }
  5226. }
  5227. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5228. asASSERT( funcs.GetLength() <= 1 );
  5229. if( funcs.GetLength() == 1 )
  5230. {
  5231. cost = asCC_TO_OBJECT_CONV;
  5232. if( generateCode )
  5233. {
  5234. // Allocate a temporary variable of the requested type
  5235. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5236. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5237. // Pass the reference of that variable to the function as output parameter
  5238. asCDataType toRef(to);
  5239. toRef.MakeReference(false);
  5240. asCArray<asSExprContext *> args;
  5241. asSExprContext arg(engine);
  5242. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5243. // Don't mark the variable as temporary, so it won't be freed too early
  5244. arg.type.SetVariable(toRef, stackOffset, false);
  5245. arg.type.isLValue = true;
  5246. arg.exprNode = node;
  5247. args.PushLast(&arg);
  5248. // Call the behaviour method
  5249. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  5250. // Use the reference to the variable as the result of the expression
  5251. // Now we can mark the variable as temporary
  5252. ctx->type.SetVariable(toRef, stackOffset, true);
  5253. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5254. }
  5255. else
  5256. {
  5257. // All casts are legal
  5258. ctx->type.Set(to);
  5259. }
  5260. }
  5261. }
  5262. }
  5263. return cost;
  5264. }
  5265. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5266. {
  5267. // First try a ref cast
  5268. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  5269. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  5270. // construct the object through any of the available constructors
  5271. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  5272. {
  5273. asCArray<int> funcs;
  5274. funcs = to.GetObjectType()->beh.constructors;
  5275. asCArray<asSExprContext *> args;
  5276. args.PushLast(ctx);
  5277. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  5278. // Did we find a matching constructor?
  5279. if( funcs.GetLength() == 1 )
  5280. {
  5281. if( generateCode )
  5282. {
  5283. // If the ASHANDLE receives a variable type parameter, then we need to
  5284. // make sure the expression is treated as a handle and not as a value
  5285. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  5286. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  5287. {
  5288. if( !ctx->type.isExplicitHandle )
  5289. {
  5290. asCDataType toHandle = ctx->type.dataType;
  5291. toHandle.MakeHandle(true);
  5292. toHandle.MakeReference(true);
  5293. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  5294. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  5295. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5296. }
  5297. ctx->type.isExplicitHandle = true;
  5298. }
  5299. // TODO: This should really reuse the code from CompileConstructCall
  5300. // Allocate the new object
  5301. asCTypeInfo tempObj;
  5302. tempObj.dataType = to;
  5303. tempObj.dataType.MakeReference(false);
  5304. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  5305. tempObj.dataType.MakeReference(true);
  5306. tempObj.isTemporary = true;
  5307. tempObj.isVariable = true;
  5308. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5309. // Push the address of the object on the stack
  5310. asSExprContext e(engine);
  5311. if( onHeap )
  5312. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5313. PrepareFunctionCall(funcs[0], &e.bc, args);
  5314. MoveArgsToStack(funcs[0], &e.bc, args, false);
  5315. // If the object is allocated on the stack, then call the constructor as a normal function
  5316. if( onHeap )
  5317. {
  5318. int offset = 0;
  5319. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5320. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  5321. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5322. }
  5323. else
  5324. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5325. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  5326. // Add tag that the object has been initialized
  5327. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  5328. // The constructor doesn't return anything,
  5329. // so we have to manually inform the type of
  5330. // the return value
  5331. e.type = tempObj;
  5332. if( !onHeap )
  5333. e.type.dataType.MakeReference(false);
  5334. // Push the address of the object on the stack again
  5335. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5336. MergeExprBytecodeAndType(ctx, &e);
  5337. }
  5338. else
  5339. {
  5340. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  5341. }
  5342. }
  5343. }
  5344. // If the base type is still different, and we are allowed to instance
  5345. // another object then we can try an implicit value cast
  5346. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  5347. {
  5348. // Attempt implicit value cast
  5349. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  5350. }
  5351. // If we still haven't converted the base type to the correct type, then there is
  5352. // no need to continue as it is not possible to do the conversion
  5353. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  5354. return asCC_NO_CONV;
  5355. if( to.IsObjectHandle() )
  5356. {
  5357. // There is no extra cost in converting to a handle
  5358. // reference to handle -> handle
  5359. // reference -> handle
  5360. // object -> handle
  5361. // handle -> reference to handle
  5362. // reference -> reference to handle
  5363. // object -> reference to handle
  5364. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  5365. // If the rvalue is a handle to a const object, then
  5366. // the lvalue must also be a handle to a const object
  5367. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  5368. {
  5369. if( convType != asIC_IMPLICIT_CONV )
  5370. {
  5371. asASSERT(node);
  5372. asCString str;
  5373. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  5374. Error(str, node);
  5375. }
  5376. }
  5377. if( !ctx->type.dataType.IsObjectHandle() )
  5378. {
  5379. // An object type can be directly converted to a handle of the
  5380. // same type by doing a ref copy to a new variable
  5381. if( ctx->type.dataType.SupportHandles() )
  5382. {
  5383. asCDataType dt = ctx->type.dataType;
  5384. dt.MakeHandle(true);
  5385. dt.MakeReference(false);
  5386. if( generateCode )
  5387. {
  5388. // If the expression is already a local variable, then it is not
  5389. // necessary to do a ref copy, as the ref objects on the stack are
  5390. // really handles, only the handles cannot be modified.
  5391. if( ctx->type.isVariable )
  5392. {
  5393. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  5394. ctx->type.dataType.MakeReadOnly(false);
  5395. ctx->type.dataType.MakeHandle(true);
  5396. ctx->type.dataType.MakeReadOnly(true);
  5397. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  5398. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5399. {
  5400. ctx->bc.Instr(asBC_PopPtr);
  5401. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  5402. ctx->type.dataType.MakeReference(true);
  5403. }
  5404. else if( ctx->type.dataType.IsReference() )
  5405. {
  5406. ctx->bc.Instr(asBC_RDSPtr);
  5407. ctx->type.dataType.MakeReference(false);
  5408. }
  5409. }
  5410. else
  5411. {
  5412. int offset = AllocateVariable(dt, true);
  5413. if( ctx->type.dataType.IsReference() )
  5414. ctx->bc.Instr(asBC_RDSPtr);
  5415. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5416. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  5417. ctx->bc.Instr(asBC_PopPtr);
  5418. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5419. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5420. if( to.IsReference() )
  5421. dt.MakeReference(true);
  5422. else
  5423. ctx->bc.Instr(asBC_RDSPtr);
  5424. ctx->type.SetVariable(dt, offset, true);
  5425. }
  5426. }
  5427. else
  5428. ctx->type.dataType = dt;
  5429. // When this conversion is done the expression is no longer an lvalue
  5430. ctx->type.isLValue = false;
  5431. }
  5432. }
  5433. if( ctx->type.dataType.IsObjectHandle() )
  5434. {
  5435. // A handle to non-const can be converted to a
  5436. // handle to const, but not the other way
  5437. if( to.IsHandleToConst() )
  5438. ctx->type.dataType.MakeHandleToConst(true);
  5439. // A const handle can be converted to a non-const
  5440. // handle and vice versa as the handle is just a value
  5441. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5442. }
  5443. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5444. {
  5445. if( generateCode )
  5446. {
  5447. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5448. // If the input type is a handle, then a simple ref copy is enough
  5449. bool isExplicitHandle = ctx->type.isExplicitHandle;
  5450. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  5451. // If the input type is read-only we'll need to temporarily
  5452. // remove this constness, otherwise the assignment will fail
  5453. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5454. ctx->type.dataType.MakeReadOnly(false);
  5455. // If the object already is a temporary variable, then the copy
  5456. // doesn't have to be made as it is already a unique object
  5457. PrepareTemporaryObject(node, ctx);
  5458. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5459. ctx->type.isExplicitHandle = isExplicitHandle;
  5460. }
  5461. // A non-reference can be converted to a reference,
  5462. // by putting the value in a temporary variable
  5463. ctx->type.dataType.MakeReference(true);
  5464. // Since it is a new temporary variable it doesn't have to be const
  5465. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5466. }
  5467. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  5468. {
  5469. Dereference(ctx, generateCode);
  5470. }
  5471. }
  5472. else // if( !to.IsObjectHandle() )
  5473. {
  5474. if( !to.IsReference() )
  5475. {
  5476. // reference to handle -> object
  5477. // handle -> object
  5478. // reference -> object
  5479. // An implicit handle can be converted to an object by adding a check for null pointer
  5480. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  5481. {
  5482. if( generateCode )
  5483. {
  5484. if( ctx->type.dataType.IsReference() )
  5485. {
  5486. // The pointer on the stack refers to the handle
  5487. ctx->bc.Instr(asBC_ChkRefS);
  5488. }
  5489. else
  5490. {
  5491. // The pointer on the stack refers to the object
  5492. ctx->bc.Instr(asBC_CHKREF);
  5493. }
  5494. }
  5495. ctx->type.dataType.MakeHandle(false);
  5496. }
  5497. // A const object can be converted to a non-const object through a copy
  5498. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  5499. allowObjectConstruct )
  5500. {
  5501. // Does the object type allow a copy to be made?
  5502. if( ctx->type.dataType.CanBeCopied() )
  5503. {
  5504. if( generateCode )
  5505. {
  5506. // Make a temporary object with the copy
  5507. PrepareTemporaryObject(node, ctx);
  5508. }
  5509. // In case the object was already in a temporary variable, then the function
  5510. // didn't really do anything so we need to remove the constness here
  5511. ctx->type.dataType.MakeReadOnly(false);
  5512. // Add the cost for the copy
  5513. cost += asCC_TO_OBJECT_CONV;
  5514. }
  5515. }
  5516. if( ctx->type.dataType.IsReference() )
  5517. {
  5518. // This may look strange, but a value type allocated on the stack is already
  5519. // correct, so nothing should be done other than remove the mark as reference.
  5520. // For types allocated on the heap, it is necessary to dereference the pointer
  5521. // that is currently on the stack
  5522. if( IsVariableOnHeap(ctx->type.stackOffset) )
  5523. Dereference(ctx, generateCode);
  5524. else
  5525. ctx->type.dataType.MakeReference(false);
  5526. }
  5527. // A non-const object can be converted to a const object directly
  5528. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  5529. {
  5530. ctx->type.dataType.MakeReadOnly(true);
  5531. }
  5532. }
  5533. else // if( to.IsReference() )
  5534. {
  5535. // reference to handle -> reference
  5536. // handle -> reference
  5537. // object -> reference
  5538. if( ctx->type.dataType.IsReference() )
  5539. {
  5540. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  5541. {
  5542. // ASHANDLE objects are really value types, so explicit handle can be removed
  5543. ctx->type.isExplicitHandle = false;
  5544. ctx->type.dataType.MakeHandle(false);
  5545. }
  5546. // A reference to a handle can be converted to a reference to an object
  5547. // by first reading the address, then verifying that it is not null
  5548. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  5549. {
  5550. ctx->type.dataType.MakeHandle(false);
  5551. if( generateCode )
  5552. ctx->bc.Instr(asBC_ChkRefS);
  5553. }
  5554. // A reference to a non-const can be converted to a reference to a const
  5555. if( to.IsReadOnly() )
  5556. ctx->type.dataType.MakeReadOnly(true);
  5557. else if( ctx->type.dataType.IsReadOnly() )
  5558. {
  5559. // A reference to a const can be converted to a reference to a
  5560. // non-const by copying the object to a temporary variable
  5561. ctx->type.dataType.MakeReadOnly(false);
  5562. if( generateCode )
  5563. {
  5564. // If the object already is a temporary variable, then the copy
  5565. // doesn't have to be made as it is already a unique object
  5566. PrepareTemporaryObject(node, ctx);
  5567. }
  5568. // Add the cost for the copy
  5569. cost += asCC_TO_OBJECT_CONV;
  5570. }
  5571. }
  5572. else // if( !ctx->type.dataType.IsReference() )
  5573. {
  5574. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  5575. if( ctx->type.dataType.IsObjectHandle() )
  5576. {
  5577. bool readOnly = false;
  5578. if( ctx->type.dataType.IsHandleToConst() )
  5579. readOnly = true;
  5580. if( generateCode )
  5581. {
  5582. if( ctx->type.isVariable )
  5583. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  5584. else
  5585. ctx->bc.Instr(asBC_CHKREF);
  5586. }
  5587. ctx->type.dataType.MakeHandle(false);
  5588. ctx->type.dataType.MakeReference(true);
  5589. // Make sure a handle to const isn't converted to non-const reference
  5590. if( readOnly )
  5591. ctx->type.dataType.MakeReadOnly(true);
  5592. }
  5593. else
  5594. {
  5595. // A value type allocated on the stack is differentiated
  5596. // by it not being a reference. But it can be handled as
  5597. // reference by pushing the pointer on the stack
  5598. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  5599. (ctx->type.isVariable || ctx->type.isTemporary) &&
  5600. !IsVariableOnHeap(ctx->type.stackOffset) )
  5601. {
  5602. // Actually the pointer is already pushed on the stack in
  5603. // CompileVariableAccess, so we don't need to do anything else
  5604. }
  5605. else if( generateCode )
  5606. {
  5607. // A non-reference can be converted to a reference,
  5608. // by putting the value in a temporary variable
  5609. // If the input type is read-only we'll need to temporarily
  5610. // remove this constness, otherwise the assignment will fail
  5611. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5612. ctx->type.dataType.MakeReadOnly(false);
  5613. // If the object already is a temporary variable, then the copy
  5614. // doesn't have to be made as it is already a unique object
  5615. PrepareTemporaryObject(node, ctx);
  5616. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5617. // Add the cost for the copy
  5618. cost += asCC_TO_OBJECT_CONV;
  5619. }
  5620. // This may look strange as the conversion was to make the expression a reference
  5621. // but a value type allocated on the stack is a reference even without the type
  5622. // being marked as such.
  5623. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  5624. }
  5625. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  5626. // Since it is a new temporary variable it doesn't have to be const
  5627. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5628. }
  5629. }
  5630. }
  5631. return cost;
  5632. }
  5633. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  5634. {
  5635. // Reference types currently don't allow implicit conversion from primitive to object
  5636. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  5637. asCObjectType *objType = to.GetObjectType();
  5638. asASSERT( objType );
  5639. if( !objType || (objType->flags & asOBJ_REF) )
  5640. return asCC_NO_CONV;
  5641. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  5642. asCArray<int> funcs;
  5643. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  5644. {
  5645. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  5646. if( func->parameterTypes.GetLength() == 1 &&
  5647. func->parameterTypes[0].IsPrimitive() &&
  5648. !(func->inOutFlags[0] & asTM_OUTREF) )
  5649. {
  5650. funcs.PushLast(func->id);
  5651. }
  5652. }
  5653. if( funcs.GetLength() == 0 )
  5654. return asCC_NO_CONV;
  5655. // Check if it is possible to choose a best match
  5656. asSExprContext arg(engine);
  5657. arg.type = ctx->type;
  5658. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  5659. asCArray<asSExprContext*> args;
  5660. args.PushLast(&arg);
  5661. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  5662. if( funcs.GetLength() != 1 )
  5663. return asCC_NO_CONV;
  5664. if( !generateCode )
  5665. {
  5666. ctx->type.Set(to);
  5667. return cost;
  5668. }
  5669. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  5670. // Clear the type of ctx, as the type is moved to the arg
  5671. ctx->type.SetDummy();
  5672. // Value types and script types are allocated through the constructor
  5673. asCTypeInfo tempObj;
  5674. tempObj.dataType = to;
  5675. tempObj.stackOffset = (short)AllocateVariable(to, true);
  5676. tempObj.dataType.MakeReference(true);
  5677. tempObj.isTemporary = true;
  5678. tempObj.isVariable = true;
  5679. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5680. // Push the address of the object on the stack
  5681. if( onHeap )
  5682. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5683. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  5684. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  5685. if( !(objType->flags & asOBJ_REF) )
  5686. {
  5687. // If the object is allocated on the stack, then call the constructor as a normal function
  5688. if( onHeap )
  5689. {
  5690. int offset = 0;
  5691. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5692. for( asUINT n = 0; n < args.GetLength(); n++ )
  5693. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  5694. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5695. }
  5696. else
  5697. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5698. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  5699. // Add tag that the object has been initialized
  5700. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  5701. // The constructor doesn't return anything,
  5702. // so we have to manually inform the type of
  5703. // the return value
  5704. ctx->type = tempObj;
  5705. if( !onHeap )
  5706. ctx->type.dataType.MakeReference(false);
  5707. // Push the address of the object on the stack again
  5708. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5709. }
  5710. else
  5711. {
  5712. asASSERT( objType->flags & asOBJ_SCOPED );
  5713. // Call the factory to create the reference type
  5714. PerformFunctionCall(funcs[0], ctx, false, &args);
  5715. }
  5716. return cost;
  5717. }
  5718. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  5719. {
  5720. asASSERT(from->type.isConstant);
  5721. // TODO: node should be the node of the value that is
  5722. // converted (not the operator that provokes the implicit
  5723. // conversion)
  5724. // If the base type is correct there is no more to do
  5725. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  5726. // References cannot be constants
  5727. if( from->type.dataType.IsReference() ) return;
  5728. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5729. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5730. {
  5731. if( from->type.dataType.IsFloatType() ||
  5732. from->type.dataType.IsDoubleType() ||
  5733. from->type.dataType.IsUnsignedType() ||
  5734. from->type.dataType.IsIntegerType() )
  5735. {
  5736. // Transform the value
  5737. // Float constants can be implicitly converted to int
  5738. if( from->type.dataType.IsFloatType() )
  5739. {
  5740. float fc = from->type.floatValue;
  5741. int ic = int(fc);
  5742. if( float(ic) != fc )
  5743. {
  5744. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5745. }
  5746. from->type.intValue = ic;
  5747. }
  5748. // Double constants can be implicitly converted to int
  5749. else if( from->type.dataType.IsDoubleType() )
  5750. {
  5751. double fc = from->type.doubleValue;
  5752. int ic = int(fc);
  5753. if( double(ic) != fc )
  5754. {
  5755. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5756. }
  5757. from->type.intValue = ic;
  5758. }
  5759. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5760. {
  5761. // Verify that it is possible to convert to signed without getting negative
  5762. if( from->type.intValue < 0 )
  5763. {
  5764. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5765. }
  5766. // Convert to 32bit
  5767. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5768. from->type.intValue = from->type.byteValue;
  5769. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5770. from->type.intValue = from->type.wordValue;
  5771. }
  5772. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5773. {
  5774. // Convert to 32bit
  5775. from->type.intValue = int(from->type.qwordValue);
  5776. }
  5777. else if( from->type.dataType.IsIntegerType() &&
  5778. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5779. {
  5780. // Convert to 32bit
  5781. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5782. from->type.intValue = (signed char)from->type.byteValue;
  5783. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5784. from->type.intValue = (short)from->type.wordValue;
  5785. }
  5786. // Set the resulting type
  5787. if( to.IsEnumType() )
  5788. from->type.dataType = to;
  5789. else
  5790. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  5791. }
  5792. // Check if a downsize is necessary
  5793. if( to.IsIntegerType() &&
  5794. from->type.dataType.IsIntegerType() &&
  5795. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5796. {
  5797. // Verify if it is possible
  5798. if( to.GetSizeInMemoryBytes() == 1 )
  5799. {
  5800. if( char(from->type.intValue) != from->type.intValue )
  5801. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5802. from->type.byteValue = char(from->type.intValue);
  5803. }
  5804. else if( to.GetSizeInMemoryBytes() == 2 )
  5805. {
  5806. if( short(from->type.intValue) != from->type.intValue )
  5807. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5808. from->type.wordValue = short(from->type.intValue);
  5809. }
  5810. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5811. }
  5812. }
  5813. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5814. {
  5815. // Float constants can be implicitly converted to int
  5816. if( from->type.dataType.IsFloatType() )
  5817. {
  5818. float fc = from->type.floatValue;
  5819. asINT64 ic = asINT64(fc);
  5820. if( float(ic) != fc )
  5821. {
  5822. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5823. }
  5824. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5825. from->type.qwordValue = ic;
  5826. }
  5827. // Double constants can be implicitly converted to int
  5828. else if( from->type.dataType.IsDoubleType() )
  5829. {
  5830. double fc = from->type.doubleValue;
  5831. asINT64 ic = asINT64(fc);
  5832. if( double(ic) != fc )
  5833. {
  5834. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5835. }
  5836. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5837. from->type.qwordValue = ic;
  5838. }
  5839. else if( from->type.dataType.IsUnsignedType() )
  5840. {
  5841. // Convert to 64bit
  5842. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5843. from->type.qwordValue = from->type.byteValue;
  5844. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5845. from->type.qwordValue = from->type.wordValue;
  5846. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5847. from->type.qwordValue = from->type.dwordValue;
  5848. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  5849. {
  5850. if( asINT64(from->type.qwordValue) < 0 )
  5851. {
  5852. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5853. }
  5854. }
  5855. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5856. }
  5857. else if( from->type.dataType.IsIntegerType() )
  5858. {
  5859. // Convert to 64bit
  5860. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5861. from->type.qwordValue = (signed char)from->type.byteValue;
  5862. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5863. from->type.qwordValue = (short)from->type.wordValue;
  5864. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5865. from->type.qwordValue = from->type.intValue;
  5866. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5867. }
  5868. }
  5869. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5870. {
  5871. if( from->type.dataType.IsFloatType() )
  5872. {
  5873. float fc = from->type.floatValue;
  5874. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  5875. // To maintain a consistent behaviour across compilers we convert to int first.
  5876. asUINT uic = asUINT(int(fc));
  5877. if( float(uic) != fc )
  5878. {
  5879. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5880. }
  5881. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5882. from->type.intValue = uic;
  5883. // Try once more, in case of a smaller type
  5884. ImplicitConversionConstant(from, to, node, convType);
  5885. }
  5886. else if( from->type.dataType.IsDoubleType() )
  5887. {
  5888. double fc = from->type.doubleValue;
  5889. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  5890. // To maintain a consistent behaviour across compilers we convert to int first.
  5891. asUINT uic = asUINT(int(fc));
  5892. if( double(uic) != fc )
  5893. {
  5894. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5895. }
  5896. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5897. from->type.intValue = uic;
  5898. // Try once more, in case of a smaller type
  5899. ImplicitConversionConstant(from, to, node, convType);
  5900. }
  5901. else if( from->type.dataType.IsIntegerType() )
  5902. {
  5903. // Verify that it is possible to convert to unsigned without loosing negative
  5904. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) ||
  5905. (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) )
  5906. {
  5907. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5908. }
  5909. // Check if any data is lost
  5910. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF )
  5911. {
  5912. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5913. }
  5914. // Convert to 32bit
  5915. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5916. from->type.intValue = (signed char)from->type.byteValue;
  5917. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5918. from->type.intValue = (short)from->type.wordValue;
  5919. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5920. // Try once more, in case of a smaller type
  5921. ImplicitConversionConstant(from, to, node, convType);
  5922. }
  5923. else if( from->type.dataType.IsUnsignedType() &&
  5924. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5925. {
  5926. // Convert to 32bit
  5927. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5928. from->type.dwordValue = from->type.byteValue;
  5929. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5930. from->type.dwordValue = from->type.wordValue;
  5931. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5932. // Try once more, in case of a smaller type
  5933. ImplicitConversionConstant(from, to, node, convType);
  5934. }
  5935. else if( from->type.dataType.IsUnsignedType() &&
  5936. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5937. {
  5938. // Verify if it is possible
  5939. if( to.GetSizeInMemoryBytes() == 1 )
  5940. {
  5941. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  5942. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5943. from->type.byteValue = asBYTE(from->type.dwordValue);
  5944. }
  5945. else if( to.GetSizeInMemoryBytes() == 2 )
  5946. {
  5947. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  5948. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5949. from->type.wordValue = asWORD(from->type.dwordValue);
  5950. }
  5951. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5952. }
  5953. }
  5954. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5955. {
  5956. if( from->type.dataType.IsFloatType() )
  5957. {
  5958. float fc = from->type.floatValue;
  5959. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5960. asQWORD uic = asQWORD(asINT64(fc));
  5961. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5962. // MSVC6 doesn't support this conversion
  5963. if( float(uic) != fc )
  5964. {
  5965. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5966. }
  5967. #endif
  5968. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5969. from->type.qwordValue = uic;
  5970. }
  5971. else if( from->type.dataType.IsDoubleType() )
  5972. {
  5973. double fc = from->type.doubleValue;
  5974. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5975. asQWORD uic = asQWORD(asINT64(fc));
  5976. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5977. // MSVC6 doesn't support this conversion
  5978. if( double(uic) != fc )
  5979. {
  5980. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5981. }
  5982. #endif
  5983. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5984. from->type.qwordValue = uic;
  5985. }
  5986. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5987. {
  5988. // Convert to 64bit
  5989. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5990. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  5991. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5992. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  5993. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5994. from->type.qwordValue = (asINT64)from->type.intValue;
  5995. // Verify that it is possible to convert to unsigned without loosing negative
  5996. if( asINT64(from->type.qwordValue) < 0 )
  5997. {
  5998. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5999. }
  6000. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6001. }
  6002. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6003. {
  6004. // Verify that it is possible to convert to unsigned without loosing negative
  6005. if( asINT64(from->type.qwordValue) < 0 )
  6006. {
  6007. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6008. }
  6009. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6010. }
  6011. else if( from->type.dataType.IsUnsignedType() )
  6012. {
  6013. // Convert to 64bit
  6014. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6015. from->type.qwordValue = from->type.byteValue;
  6016. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6017. from->type.qwordValue = from->type.wordValue;
  6018. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6019. from->type.qwordValue = from->type.dwordValue;
  6020. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6021. }
  6022. }
  6023. else if( to.IsFloatType() )
  6024. {
  6025. if( from->type.dataType.IsDoubleType() )
  6026. {
  6027. double ic = from->type.doubleValue;
  6028. float fc = float(ic);
  6029. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6030. from->type.floatValue = fc;
  6031. }
  6032. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6033. {
  6034. // Must properly convert value in case the from value is smaller
  6035. int ic;
  6036. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6037. ic = (signed char)from->type.byteValue;
  6038. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6039. ic = (short)from->type.wordValue;
  6040. else
  6041. ic = from->type.intValue;
  6042. float fc = float(ic);
  6043. if( int(fc) != ic )
  6044. {
  6045. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6046. }
  6047. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6048. from->type.floatValue = fc;
  6049. }
  6050. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6051. {
  6052. float fc = float(asINT64(from->type.qwordValue));
  6053. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  6054. {
  6055. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6056. }
  6057. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6058. from->type.floatValue = fc;
  6059. }
  6060. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6061. {
  6062. // Must properly convert value in case the from value is smaller
  6063. unsigned int uic;
  6064. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6065. uic = from->type.byteValue;
  6066. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6067. uic = from->type.wordValue;
  6068. else
  6069. uic = from->type.dwordValue;
  6070. float fc = float(uic);
  6071. if( (unsigned int)(fc) != uic )
  6072. {
  6073. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6074. }
  6075. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6076. from->type.floatValue = fc;
  6077. }
  6078. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6079. {
  6080. float fc = float((asINT64)from->type.qwordValue);
  6081. if( asQWORD(fc) != from->type.qwordValue )
  6082. {
  6083. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6084. }
  6085. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6086. from->type.floatValue = fc;
  6087. }
  6088. }
  6089. else if( to.IsDoubleType() )
  6090. {
  6091. if( from->type.dataType.IsFloatType() )
  6092. {
  6093. float ic = from->type.floatValue;
  6094. double fc = double(ic);
  6095. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6096. from->type.doubleValue = fc;
  6097. }
  6098. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6099. {
  6100. // Must properly convert value in case the from value is smaller
  6101. int ic;
  6102. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6103. ic = (signed char)from->type.byteValue;
  6104. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6105. ic = (short)from->type.wordValue;
  6106. else
  6107. ic = from->type.intValue;
  6108. double fc = double(ic);
  6109. if( int(fc) != ic )
  6110. {
  6111. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6112. }
  6113. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6114. from->type.doubleValue = fc;
  6115. }
  6116. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6117. {
  6118. double fc = double(asINT64(from->type.qwordValue));
  6119. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  6120. {
  6121. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6122. }
  6123. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6124. from->type.doubleValue = fc;
  6125. }
  6126. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6127. {
  6128. // Must properly convert value in case the from value is smaller
  6129. unsigned int uic;
  6130. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6131. uic = from->type.byteValue;
  6132. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6133. uic = from->type.wordValue;
  6134. else
  6135. uic = from->type.dwordValue;
  6136. double fc = double(uic);
  6137. if( (unsigned int)(fc) != uic )
  6138. {
  6139. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6140. }
  6141. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6142. from->type.doubleValue = fc;
  6143. }
  6144. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6145. {
  6146. double fc = double((asINT64)from->type.qwordValue);
  6147. if( asQWORD(fc) != from->type.qwordValue )
  6148. {
  6149. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6150. }
  6151. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  6152. from->type.doubleValue = fc;
  6153. }
  6154. }
  6155. }
  6156. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  6157. {
  6158. // Don't allow any operators on expressions that take address of class method
  6159. // If methodName is set but the type is not an object, then it is a global function
  6160. if( lctx->methodName != "" || rctx->IsClassMethod() )
  6161. {
  6162. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  6163. return -1;
  6164. }
  6165. // Implicit handle types should always be treated as handles in assignments
  6166. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6167. {
  6168. lctx->type.dataType.MakeHandle(true);
  6169. lctx->type.isExplicitHandle = true;
  6170. }
  6171. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  6172. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  6173. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  6174. !lctx->type.dataType.GetBehaviour()->copy)
  6175. lctx->type.isExplicitHandle = true;
  6176. // If the left hand expression is a property accessor, then that should be used
  6177. // to do the assignment instead of the ordinary operator. The exception is when
  6178. // the property accessor is for a handle property, and the operation is a value
  6179. // assignment.
  6180. if( (lctx->property_get || lctx->property_set) &&
  6181. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  6182. {
  6183. if( op != ttAssignment )
  6184. {
  6185. // TODO: getset: We may actually be able to support this, if we can
  6186. // guarantee that the object reference will stay valid
  6187. // between the calls to the get and set accessors.
  6188. // Process the property to free the memory
  6189. ProcessPropertySetAccessor(lctx, rctx, opNode);
  6190. // Compound assignments are not allowed for properties
  6191. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  6192. return -1;
  6193. }
  6194. // It is not allowed to do a handle assignment on a property
  6195. // accessor that doesn't take a handle in the set accessor.
  6196. if( lctx->property_set && lctx->type.isExplicitHandle )
  6197. {
  6198. // set_opIndex has 2 arguments, where as normal setters have only 1
  6199. asCArray<asCDataType>& parameterTypes =
  6200. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  6201. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  6202. {
  6203. // Process the property to free the memory
  6204. ProcessPropertySetAccessor(lctx, rctx, opNode);
  6205. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  6206. return -1;
  6207. }
  6208. }
  6209. MergeExprBytecodeAndType(ctx, lctx);
  6210. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  6211. }
  6212. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6213. {
  6214. // Get the handle to the object that will be used for the value assignment
  6215. ProcessPropertyGetAccessor(lctx, opNode);
  6216. }
  6217. if( lctx->type.dataType.IsPrimitive() )
  6218. {
  6219. if( !lctx->type.isLValue )
  6220. {
  6221. Error(TXT_NOT_LVALUE, lexpr);
  6222. return -1;
  6223. }
  6224. if( op != ttAssignment )
  6225. {
  6226. // Compute the operator before the assignment
  6227. asCTypeInfo lvalue = lctx->type;
  6228. if( lctx->type.isTemporary && !lctx->type.isVariable )
  6229. {
  6230. // The temporary variable must not be freed until the
  6231. // assignment has been performed. lvalue still holds
  6232. // the information about the temporary variable
  6233. lctx->type.isTemporary = false;
  6234. }
  6235. asSExprContext o(engine);
  6236. CompileOperator(opNode, lctx, rctx, &o);
  6237. MergeExprBytecode(rctx, &o);
  6238. rctx->type = o.type;
  6239. // Convert the rvalue to the right type and validate it
  6240. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  6241. MergeExprBytecode(ctx, rctx);
  6242. lctx->type = lvalue;
  6243. // The lvalue continues the same, either it was a variable, or a reference in the register
  6244. }
  6245. else
  6246. {
  6247. // Convert the rvalue to the right type and validate it
  6248. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  6249. MergeExprBytecode(ctx, rctx);
  6250. MergeExprBytecode(ctx, lctx);
  6251. }
  6252. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6253. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6254. ctx->type = lctx->type;
  6255. }
  6256. else if( lctx->type.isExplicitHandle )
  6257. {
  6258. if( !lctx->type.isLValue )
  6259. {
  6260. Error(TXT_NOT_LVALUE, lexpr);
  6261. return -1;
  6262. }
  6263. // Object handles don't have any compound assignment operators
  6264. if( op != ttAssignment )
  6265. {
  6266. asCString str;
  6267. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  6268. Error(str, lexpr);
  6269. return -1;
  6270. }
  6271. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  6272. {
  6273. // The object is a value type but that should be treated as a handle
  6274. // Make sure the right hand value is a handle
  6275. if( !rctx->type.isExplicitHandle &&
  6276. !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  6277. {
  6278. // Function names can be considered handles already
  6279. if( rctx->methodName == "" )
  6280. {
  6281. asCDataType dt = rctx->type.dataType;
  6282. dt.MakeHandle(true);
  6283. dt.MakeReference(false);
  6284. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  6285. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6286. {
  6287. asCString str;
  6288. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  6289. Error(str, rexpr);
  6290. return -1;
  6291. }
  6292. }
  6293. }
  6294. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx, true) )
  6295. {
  6296. // An overloaded assignment operator was found (or a compilation error occured)
  6297. return 0;
  6298. }
  6299. // The object must implement the opAssign method
  6300. asCString msg;
  6301. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format().AddressOf());
  6302. Error(msg.AddressOf(), opNode);
  6303. return -1;
  6304. }
  6305. else
  6306. {
  6307. asCDataType dt = lctx->type.dataType;
  6308. dt.MakeReference(false);
  6309. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
  6310. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6311. {
  6312. asCString str;
  6313. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  6314. Error(str, rexpr);
  6315. return -1;
  6316. }
  6317. MergeExprBytecode(ctx, rctx);
  6318. MergeExprBytecode(ctx, lctx);
  6319. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6320. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6321. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6322. ctx->type = lctx->type;
  6323. // After the handle assignment the original handle is left on the stack
  6324. ctx->type.dataType.MakeReference(false);
  6325. }
  6326. }
  6327. else // if( lctx->type.dataType.IsObject() )
  6328. {
  6329. // The lvalue reference may be marked as a temporary, if for example
  6330. // it was originated as a handle returned from a function. In such
  6331. // cases it must be possible to assign values to it anyway.
  6332. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6333. {
  6334. // Convert the handle to a object reference
  6335. asCDataType to;
  6336. to = lctx->type.dataType;
  6337. to.MakeHandle(false);
  6338. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  6339. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  6340. }
  6341. // Check for overloaded assignment operator
  6342. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  6343. {
  6344. // An overloaded assignment operator was found (or a compilation error occured)
  6345. return 0;
  6346. }
  6347. // No registered operator was found. In case the operation is a direct
  6348. // assignment and the rvalue is the same type as the lvalue, then we can
  6349. // still use the byte-for-byte copy to do the assignment
  6350. if( op != ttAssignment )
  6351. {
  6352. asCString str;
  6353. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  6354. Error(str, lexpr);
  6355. return -1;
  6356. }
  6357. // If the left hand expression is simple, i.e. without any
  6358. // function calls or allocations of memory, then we can avoid
  6359. // doing a copy of the right hand expression (done by PrepareArgument).
  6360. // Instead the reference to the value can be placed directly on the
  6361. // stack.
  6362. //
  6363. // This optimization should only be done for value types, where
  6364. // the application developer is responsible for making the
  6365. // implementation safe against unwanted destruction of the input
  6366. // reference before the time.
  6367. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  6368. // Implicitly convert the rvalue to the type of the lvalue
  6369. bool needConversion = false;
  6370. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6371. needConversion = true;
  6372. if( !simpleExpr || needConversion )
  6373. {
  6374. asCDataType dt = lctx->type.dataType;
  6375. dt.MakeReference(true);
  6376. dt.MakeReadOnly(true);
  6377. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  6378. if( r < 0 )
  6379. return -1;
  6380. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6381. {
  6382. asCString str;
  6383. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  6384. Error(str, rexpr);
  6385. return -1;
  6386. }
  6387. }
  6388. else
  6389. {
  6390. // Process any property accessor first, before placing the final reference on the stack
  6391. ProcessPropertyGetAccessor(rctx, rexpr);
  6392. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  6393. rctx->bc.Instr(asBC_RDSPtr);
  6394. }
  6395. MergeExprBytecode(ctx, rctx);
  6396. MergeExprBytecode(ctx, lctx);
  6397. if( !simpleExpr || needConversion )
  6398. {
  6399. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  6400. {
  6401. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  6402. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  6403. // as the value allocated on the stack is guaranteed to be safe.
  6404. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  6405. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  6406. else
  6407. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6408. }
  6409. }
  6410. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6411. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6412. ctx->type = lctx->type;
  6413. }
  6414. return 0;
  6415. }
  6416. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  6417. {
  6418. asCScriptNode *lexpr = expr->firstChild;
  6419. if( lexpr->next )
  6420. {
  6421. // Compile the two expression terms
  6422. asSExprContext lctx(engine), rctx(engine);
  6423. int rr = CompileAssignment(lexpr->next->next, &rctx);
  6424. int lr = CompileCondition(lexpr, &lctx);
  6425. if( lr >= 0 && rr >= 0 )
  6426. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  6427. // Since the operands failed, the assignment was not computed
  6428. ctx->type.SetDummy();
  6429. return -1;
  6430. }
  6431. return CompileCondition(lexpr, ctx);
  6432. }
  6433. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  6434. {
  6435. asCTypeInfo ctype;
  6436. // Compile the conditional expression
  6437. asCScriptNode *cexpr = expr->firstChild;
  6438. if( cexpr->next )
  6439. {
  6440. //-------------------------------
  6441. // Compile the condition
  6442. asSExprContext e(engine);
  6443. int r = CompileExpression(cexpr, &e);
  6444. if( r < 0 )
  6445. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6446. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6447. {
  6448. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  6449. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6450. }
  6451. ctype = e.type;
  6452. ProcessPropertyGetAccessor(&e, cexpr);
  6453. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  6454. ProcessDeferredParams(&e);
  6455. //-------------------------------
  6456. // Compile the left expression
  6457. asSExprContext le(engine);
  6458. int lr = CompileAssignment(cexpr->next, &le);
  6459. //-------------------------------
  6460. // Compile the right expression
  6461. asSExprContext re(engine);
  6462. int rr = CompileAssignment(cexpr->next->next, &re);
  6463. if( lr >= 0 && rr >= 0 )
  6464. {
  6465. // Don't allow any operators on expressions that take address of class method
  6466. if( le.IsClassMethod() || re.IsClassMethod() )
  6467. {
  6468. Error(TXT_INVALID_OP_ON_METHOD, expr);
  6469. return -1;
  6470. }
  6471. ProcessPropertyGetAccessor(&le, cexpr->next);
  6472. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  6473. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  6474. // Allow a 0 or null in the first case to be implicitly converted to the second type
  6475. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsIntegerType() )
  6476. {
  6477. asCDataType to = re.type.dataType;
  6478. to.MakeReference(false);
  6479. to.MakeReadOnly(true);
  6480. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6481. }
  6482. else if( le.type.IsNullConstant() )
  6483. {
  6484. asCDataType to = re.type.dataType;
  6485. to.MakeHandle(true);
  6486. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6487. }
  6488. // Allow either case to be converted to const @ if the other is const @
  6489. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  6490. {
  6491. le.type.dataType.MakeHandleToConst(true);
  6492. re.type.dataType.MakeHandleToConst(true);
  6493. }
  6494. //---------------------------------
  6495. // Output the byte code
  6496. int afterLabel = nextLabel++;
  6497. int elseLabel = nextLabel++;
  6498. // If left expression is void, then we don't need to store the result
  6499. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  6500. {
  6501. // Put the code for the condition expression on the output
  6502. MergeExprBytecode(ctx, &e);
  6503. // Added the branch decision
  6504. ctx->type = e.type;
  6505. ConvertToVariable(ctx);
  6506. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6507. ctx->bc.Instr(asBC_ClrHi);
  6508. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6509. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6510. // Add the left expression
  6511. MergeExprBytecode(ctx, &le);
  6512. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6513. // Add the right expression
  6514. ctx->bc.Label((short)elseLabel);
  6515. MergeExprBytecode(ctx, &re);
  6516. ctx->bc.Label((short)afterLabel);
  6517. // Make sure both expressions have the same type
  6518. if( le.type.dataType != re.type.dataType )
  6519. Error(TXT_BOTH_MUST_BE_SAME, expr);
  6520. // Set the type of the result
  6521. ctx->type = le.type;
  6522. }
  6523. else
  6524. {
  6525. // Allocate temporary variable and copy the result to that one
  6526. asCTypeInfo temp;
  6527. temp = le.type;
  6528. temp.dataType.MakeReference(false);
  6529. temp.dataType.MakeReadOnly(false);
  6530. // Make sure the variable isn't used in any of the expressions,
  6531. // as it would be overwritten which may cause crashes or less visible bugs
  6532. int l = int(reservedVariables.GetLength());
  6533. e.bc.GetVarsUsed(reservedVariables);
  6534. le.bc.GetVarsUsed(reservedVariables);
  6535. re.bc.GetVarsUsed(reservedVariables);
  6536. int offset = AllocateVariable(temp.dataType, true, false);
  6537. reservedVariables.SetLength(l);
  6538. temp.SetVariable(temp.dataType, offset, true);
  6539. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  6540. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  6541. // Put the code for the condition expression on the output
  6542. MergeExprBytecode(ctx, &e);
  6543. // Add the branch decision
  6544. ctx->type = e.type;
  6545. ConvertToVariable(ctx);
  6546. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6547. ctx->bc.Instr(asBC_ClrHi);
  6548. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6549. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6550. // Assign the result of the left expression to the temporary variable
  6551. asCTypeInfo rtemp;
  6552. rtemp = temp;
  6553. if( rtemp.dataType.IsObjectHandle() )
  6554. rtemp.isExplicitHandle = true;
  6555. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  6556. MergeExprBytecode(ctx, &le);
  6557. if( !rtemp.dataType.IsPrimitive() )
  6558. {
  6559. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6560. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  6561. }
  6562. asCTypeInfo result;
  6563. result = rtemp;
  6564. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  6565. if( !result.dataType.IsPrimitive() )
  6566. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  6567. // Release the old temporary variable
  6568. ReleaseTemporaryVariable(le.type, &ctx->bc);
  6569. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6570. // Start of the right expression
  6571. ctx->bc.Label((short)elseLabel);
  6572. // Copy the result to the same temporary variable
  6573. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  6574. MergeExprBytecode(ctx, &re);
  6575. if( !rtemp.dataType.IsPrimitive() )
  6576. {
  6577. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6578. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  6579. }
  6580. result = rtemp;
  6581. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  6582. if( !result.dataType.IsPrimitive() )
  6583. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  6584. // Release the old temporary variable
  6585. ReleaseTemporaryVariable(re.type, &ctx->bc);
  6586. ctx->bc.Label((short)afterLabel);
  6587. // Make sure both expressions have the same type
  6588. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  6589. Error(TXT_BOTH_MUST_BE_SAME, expr);
  6590. // Set the temporary variable as output
  6591. ctx->type = rtemp;
  6592. ctx->type.isExplicitHandle = isExplicitHandle;
  6593. if( !ctx->type.dataType.IsPrimitive() )
  6594. {
  6595. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6596. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  6597. }
  6598. // Make sure the output isn't marked as being a literal constant
  6599. ctx->type.isConstant = false;
  6600. }
  6601. }
  6602. else
  6603. {
  6604. ctx->type.SetDummy();
  6605. return -1;
  6606. }
  6607. }
  6608. else
  6609. return CompileExpression(cexpr, ctx);
  6610. return 0;
  6611. }
  6612. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  6613. {
  6614. asASSERT(expr->nodeType == snExpression);
  6615. // Check if this is an initialization of a temp object with an initialization list
  6616. if( expr->firstChild && expr->firstChild->nodeType == snDataType )
  6617. {
  6618. // TODO: It should be possible to infer the type of the object from where the
  6619. // expression will be used. The compilation of the initialization list
  6620. // should be deferred until it is known for what it will be used. It will
  6621. // then for example be possible to write expressions like:
  6622. //
  6623. // @dict = {{'key', 'value'}};
  6624. // funcTakingArrayOfInt({1,2,3,4});
  6625. // Determine the type of the temporary object
  6626. asCDataType dt = builder->CreateDataTypeFromNode(expr->firstChild, script, outFunc->nameSpace);
  6627. // Do not allow constructing non-shared types in shared functions
  6628. if( outFunc->IsShared() &&
  6629. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  6630. {
  6631. asCString msg;
  6632. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  6633. Error(msg, expr);
  6634. }
  6635. // Allocate and initialize the temporary object
  6636. int offset = AllocateVariable(dt, true);
  6637. CompileInitialization(expr->lastChild, &ctx->bc, dt, expr, offset, 0, 0);
  6638. // Push the reference to the object on the stack
  6639. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6640. ctx->type.SetVariable(dt, offset, true);
  6641. ctx->type.isLValue = false;
  6642. // If the variable is allocated on the heap we have a reference,
  6643. // otherwise the actual object pointer is pushed on the stack.
  6644. if( IsVariableOnHeap(offset) )
  6645. ctx->type.dataType.MakeReference(true);
  6646. return 0;
  6647. }
  6648. // Convert to polish post fix, i.e: a+b => ab+
  6649. // The algorithm that I've implemented here is similar to
  6650. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  6651. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  6652. // Count the nodes in order to preallocate the buffers
  6653. int count = 0;
  6654. asCScriptNode *node = expr->firstChild;
  6655. while( node )
  6656. {
  6657. count++;
  6658. node = node->next;
  6659. }
  6660. asCArray<asCScriptNode *> stack(count);
  6661. asCArray<asCScriptNode *> stack2(count);
  6662. node = expr->firstChild;
  6663. while( node )
  6664. {
  6665. int precedence = GetPrecedence(node);
  6666. while( stack.GetLength() > 0 &&
  6667. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  6668. stack2.PushLast(stack.PopLast());
  6669. stack.PushLast(node);
  6670. node = node->next;
  6671. }
  6672. while( stack.GetLength() > 0 )
  6673. stack2.PushLast(stack.PopLast());
  6674. // Compile the postfix formatted expression
  6675. return CompilePostFixExpression(&stack2, ctx);
  6676. }
  6677. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  6678. {
  6679. // Shouldn't send any byte code
  6680. asASSERT(ctx->bc.GetLastInstr() == -1);
  6681. // Set the context to a dummy type to avoid further
  6682. // errors in case the expression fails to compile
  6683. ctx->type.SetDummy();
  6684. // Evaluate the operands and operators
  6685. asCArray<asSExprContext*> free;
  6686. asCArray<asSExprContext*> expr;
  6687. int ret = 0;
  6688. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  6689. {
  6690. asCScriptNode *node = (*postfix)[n];
  6691. if( node->nodeType == snExprTerm )
  6692. {
  6693. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  6694. expr.PushLast(e);
  6695. e->exprNode = node;
  6696. ret = CompileExpressionTerm(node, e);
  6697. }
  6698. else
  6699. {
  6700. asSExprContext *r = expr.PopLast();
  6701. asSExprContext *l = expr.PopLast();
  6702. // Now compile the operator
  6703. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  6704. ret = CompileOperator(node, l, r, e);
  6705. expr.PushLast(e);
  6706. // Free the operands
  6707. l->Clear();
  6708. free.PushLast(l);
  6709. r->Clear();
  6710. free.PushLast(r);
  6711. }
  6712. }
  6713. if( ret == 0 )
  6714. {
  6715. asASSERT(expr.GetLength() == 1);
  6716. // The final result should be moved to the output context
  6717. MergeExprBytecodeAndType(ctx, expr[0]);
  6718. }
  6719. // Clean up
  6720. for( asUINT e = 0; e < expr.GetLength(); e++ )
  6721. asDELETE(expr[e], asSExprContext);
  6722. for( asUINT f = 0; f < free.GetLength(); f++ )
  6723. asDELETE(free[f], asSExprContext);
  6724. return ret;
  6725. }
  6726. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  6727. {
  6728. // Shouldn't send any byte code
  6729. asASSERT(ctx->bc.GetLastInstr() == -1);
  6730. // Set the type as a dummy by default, in case of any compiler errors
  6731. ctx->type.SetDummy();
  6732. // Compile the value node
  6733. asCScriptNode *vnode = node->firstChild;
  6734. while( vnode->nodeType != snExprValue )
  6735. vnode = vnode->next;
  6736. asSExprContext v(engine);
  6737. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  6738. // Compile post fix operators
  6739. asCScriptNode *pnode = vnode->next;
  6740. while( pnode )
  6741. {
  6742. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  6743. pnode = pnode->next;
  6744. }
  6745. // Compile pre fix operators
  6746. pnode = vnode->prev;
  6747. while( pnode )
  6748. {
  6749. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  6750. pnode = pnode->prev;
  6751. }
  6752. // Return the byte code and final type description
  6753. MergeExprBytecodeAndType(ctx, &v);
  6754. return 0;
  6755. }
  6756. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  6757. {
  6758. bool found = false;
  6759. // It is a local variable or parameter?
  6760. // This is not accessible by default arg expressions
  6761. sVariable *v = 0;
  6762. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  6763. v = variables->GetVariable(name.AddressOf());
  6764. if( v )
  6765. {
  6766. found = true;
  6767. if( v->isPureConstant )
  6768. ctx->type.SetConstantQW(v->type, v->constantValue);
  6769. else if( v->type.IsPrimitive() )
  6770. {
  6771. if( v->type.IsReference() )
  6772. {
  6773. // Copy the reference into the register
  6774. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  6775. ctx->bc.Instr(asBC_PopRPtr);
  6776. ctx->type.Set(v->type);
  6777. }
  6778. else
  6779. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6780. ctx->type.isLValue = true;
  6781. }
  6782. else
  6783. {
  6784. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  6785. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6786. // If the variable is allocated on the heap we have a reference,
  6787. // otherwise the actual object pointer is pushed on the stack.
  6788. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  6789. // Implicitly dereference handle parameters sent by reference
  6790. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  6791. ctx->bc.Instr(asBC_RDSPtr);
  6792. ctx->type.isLValue = true;
  6793. }
  6794. }
  6795. // Is it a class member?
  6796. // This is not accessible by default arg expressions
  6797. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  6798. {
  6799. if( name == THIS_TOKEN && !objType )
  6800. {
  6801. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  6802. // The object pointer is located at stack position 0
  6803. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6804. ctx->type.SetVariable(dt, 0, false);
  6805. ctx->type.dataType.MakeReference(true);
  6806. ctx->type.isLValue = true;
  6807. found = true;
  6808. }
  6809. if( !found )
  6810. {
  6811. // See if there are any matching property accessors
  6812. asSExprContext access(engine);
  6813. if( objType )
  6814. access.type.Set(asCDataType::CreateObject(objType, false));
  6815. else
  6816. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  6817. access.type.dataType.MakeReference(true);
  6818. int r = 0;
  6819. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6820. {
  6821. // This is an index access, check if there is a property accessor that takes an index arg
  6822. asSExprContext dummyArg(engine);
  6823. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  6824. }
  6825. if( r == 0 )
  6826. {
  6827. // Normal property access
  6828. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  6829. }
  6830. if( r < 0 ) return -1;
  6831. if( access.property_get || access.property_set )
  6832. {
  6833. if( !objType )
  6834. {
  6835. // Prepare the bytecode for the member access
  6836. // This is only done when accessing through the implicit this pointer
  6837. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6838. }
  6839. MergeExprBytecodeAndType(ctx, &access);
  6840. found = true;
  6841. }
  6842. }
  6843. if( !found )
  6844. {
  6845. asCDataType dt;
  6846. if( objType )
  6847. dt = asCDataType::CreateObject(objType, false);
  6848. else
  6849. dt = asCDataType::CreateObject(outFunc->objectType, false);
  6850. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  6851. if( prop )
  6852. {
  6853. if( !objType )
  6854. {
  6855. // The object pointer is located at stack position 0
  6856. // This is only done when accessing through the implicit this pointer
  6857. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6858. ctx->type.SetVariable(dt, 0, false);
  6859. ctx->type.dataType.MakeReference(true);
  6860. Dereference(ctx, true);
  6861. }
  6862. // TODO: This is the same as what is in CompileExpressionPostOp
  6863. // Put the offset on the stack
  6864. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  6865. if( prop->type.IsReference() )
  6866. ctx->bc.Instr(asBC_RDSPtr);
  6867. // Reference to primitive must be stored in the temp register
  6868. if( prop->type.IsPrimitive() )
  6869. {
  6870. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  6871. ctx->bc.Instr(asBC_PopRPtr);
  6872. }
  6873. // Set the new type (keeping info about temp variable)
  6874. ctx->type.dataType = prop->type;
  6875. ctx->type.dataType.MakeReference(true);
  6876. ctx->type.isVariable = false;
  6877. ctx->type.isLValue = true;
  6878. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  6879. {
  6880. // Objects that are members are not references
  6881. ctx->type.dataType.MakeReference(false);
  6882. }
  6883. // If the object reference is const, the property will also be const
  6884. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  6885. found = true;
  6886. }
  6887. else if( outFunc->objectType )
  6888. {
  6889. // If it is not a property, it may still be the name of a method which can be used to create delegates
  6890. asCObjectType *ot = outFunc->objectType;
  6891. asCScriptFunction *func = 0;
  6892. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6893. {
  6894. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  6895. {
  6896. func = engine->scriptFunctions[ot->methods[n]];
  6897. break;
  6898. }
  6899. }
  6900. if( func )
  6901. {
  6902. // An object method was found. Keep the name of the method in the expression, but
  6903. // don't actually modify the bytecode at this point since it is not yet known what
  6904. // the method will be used for, or even what overloaded method should be used.
  6905. ctx->methodName = name;
  6906. // Place the object pointer on the stack, as if the expression was this.func
  6907. if( !objType )
  6908. {
  6909. // The object pointer is located at stack position 0
  6910. // This is only done when accessing through the implicit this pointer
  6911. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6912. ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
  6913. ctx->type.dataType.MakeReference(true);
  6914. Dereference(ctx, true);
  6915. }
  6916. found = true;
  6917. }
  6918. }
  6919. }
  6920. }
  6921. // Recursively search parent namespaces for global entities
  6922. asCString currScope = scope;
  6923. if( scope == "" )
  6924. currScope = outFunc->nameSpace->name;
  6925. while( !found && !noGlobal && !objType )
  6926. {
  6927. asSNameSpace *ns = DetermineNameSpace(currScope);
  6928. // Is it a global property?
  6929. if( !found && ns )
  6930. {
  6931. // See if there are any matching global property accessors
  6932. asSExprContext access(engine);
  6933. int r = 0;
  6934. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6935. {
  6936. // This is an index access, check if there is a property accessor that takes an index arg
  6937. asSExprContext dummyArg(engine);
  6938. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  6939. }
  6940. if( r == 0 )
  6941. {
  6942. // Normal property access
  6943. r = FindPropertyAccessor(name, &access, errNode, ns);
  6944. }
  6945. if( r < 0 ) return -1;
  6946. if( access.property_get || access.property_set )
  6947. {
  6948. // Prepare the bytecode for the function call
  6949. MergeExprBytecodeAndType(ctx, &access);
  6950. found = true;
  6951. }
  6952. // See if there is any matching global property
  6953. if( !found )
  6954. {
  6955. bool isCompiled = true;
  6956. bool isPureConstant = false;
  6957. bool isAppProp = false;
  6958. asQWORD constantValue = 0;
  6959. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  6960. if( prop )
  6961. {
  6962. found = true;
  6963. // Verify that the global property has been compiled already
  6964. if( isCompiled )
  6965. {
  6966. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6967. {
  6968. ctx->type.dataType.MakeHandle(true);
  6969. ctx->type.isExplicitHandle = true;
  6970. }
  6971. // If the global property is a pure constant
  6972. // we can allow the compiler to optimize it. Pure
  6973. // constants are global constant variables that were
  6974. // initialized by literal constants.
  6975. if( isPureConstant )
  6976. ctx->type.SetConstantQW(prop->type, constantValue);
  6977. else
  6978. {
  6979. // A shared type must not access global vars, unless they
  6980. // too are shared, e.g. application registered vars
  6981. if( outFunc->IsShared() )
  6982. {
  6983. if( !isAppProp )
  6984. {
  6985. asCString str;
  6986. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  6987. Error(str, errNode);
  6988. // Allow the compilation to continue to catch other problems
  6989. }
  6990. }
  6991. ctx->type.Set(prop->type);
  6992. ctx->type.isLValue = true;
  6993. if( ctx->type.dataType.IsPrimitive() )
  6994. {
  6995. // Load the address of the variable into the register
  6996. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  6997. ctx->type.dataType.MakeReference(true);
  6998. }
  6999. else
  7000. {
  7001. // Push the address of the variable on the stack
  7002. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  7003. // If the object is a value type or a non-handle variable to a reference type,
  7004. // then we must validate the existance as it could potentially be accessed
  7005. // before it is initialized.
  7006. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  7007. !ctx->type.dataType.IsObjectHandle() )
  7008. {
  7009. // TODO: runtime optimize: This is not necessary for application registered properties
  7010. ctx->bc.Instr(asBC_ChkRefS);
  7011. }
  7012. // If the address pushed on the stack is to a value type or an object
  7013. // handle, then mark the expression as a reference. Addresses to a reference
  7014. // type aren't marked as references to get correct behaviour
  7015. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  7016. ctx->type.dataType.IsObjectHandle() )
  7017. {
  7018. ctx->type.dataType.MakeReference(true);
  7019. }
  7020. else
  7021. {
  7022. asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  7023. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  7024. ctx->bc.Instr(asBC_RDSPtr);
  7025. }
  7026. }
  7027. }
  7028. }
  7029. else
  7030. {
  7031. asCString str;
  7032. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  7033. Error(str, errNode);
  7034. return -1;
  7035. }
  7036. }
  7037. }
  7038. }
  7039. // Is it the name of a global function?
  7040. if( !noFunction && !found && ns )
  7041. {
  7042. asCArray<int> funcs;
  7043. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7044. if( funcs.GetLength() > 0 )
  7045. {
  7046. found = true;
  7047. // Defer the evaluation of which function until it is actually used
  7048. // Store the namespace and name of the function for later
  7049. ctx->type.SetUndefinedFuncHandle(engine);
  7050. ctx->methodName = ns ? ns->name + "::" + name : name;
  7051. }
  7052. }
  7053. // Is it an enum value?
  7054. if( !found )
  7055. {
  7056. // The enum type may be declared in a namespace too
  7057. asCObjectType *scopeType = 0;
  7058. if( currScope != "" && currScope != "::" )
  7059. {
  7060. // Use the last scope name as the enum type
  7061. asCString enumType = currScope;
  7062. asCString nsScope;
  7063. int p = currScope.FindLast("::");
  7064. if( p != -1 )
  7065. {
  7066. enumType = currScope.SubString(p+2);
  7067. nsScope = currScope.SubString(0, p);
  7068. }
  7069. asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
  7070. if( ns )
  7071. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  7072. }
  7073. asDWORD value = 0;
  7074. asCDataType dt;
  7075. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  7076. {
  7077. // scoped enum value found
  7078. found = true;
  7079. }
  7080. else if( !engine->ep.requireEnumScope )
  7081. {
  7082. // Look for the enum value without explicitly informing the enum type
  7083. asSNameSpace *ns = DetermineNameSpace(currScope);
  7084. int e = 0;
  7085. if( ns )
  7086. e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  7087. if( e )
  7088. {
  7089. found = true;
  7090. if( e == 2 )
  7091. {
  7092. // Ambiguous enum value: Save the name for resolution later.
  7093. // The ambiguity could be resolved now, but I hesitate
  7094. // to store too much information in the context.
  7095. ctx->enumValue = name.AddressOf();
  7096. // We cannot set a dummy value because it will pass through
  7097. // cleanly as an integer.
  7098. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  7099. return 0;
  7100. }
  7101. }
  7102. }
  7103. if( found )
  7104. {
  7105. // Even if the enum type is not shared, and we're compiling a shared object,
  7106. // the use of the values are still allowed, since they are treated as constants.
  7107. // an enum value was resolved
  7108. ctx->type.SetConstantDW(dt, value);
  7109. }
  7110. else
  7111. {
  7112. // If nothing was found because the scope doesn't match a namespace or an enum
  7113. // then this should be reported as an error and the search interrupted
  7114. if( !ns && !scopeType )
  7115. {
  7116. ctx->type.SetDummy();
  7117. asCString str;
  7118. str.Format(TXT_UNKNOWN_SCOPE_s, currScope.AddressOf());
  7119. Error(str, errNode);
  7120. return -1;
  7121. }
  7122. }
  7123. }
  7124. if( !found )
  7125. {
  7126. if( currScope == "" || currScope == "::" )
  7127. break;
  7128. // Move up to parent namespace
  7129. int pos = currScope.FindLast("::");
  7130. if( pos >= 0 )
  7131. currScope = currScope.SubString(0, pos);
  7132. else
  7133. currScope = "::";
  7134. }
  7135. }
  7136. // The name doesn't match any variable
  7137. if( !found )
  7138. {
  7139. // Give dummy value
  7140. ctx->type.SetDummy();
  7141. if( !isOptional )
  7142. {
  7143. // Prepend the scope to the name for the error message
  7144. asCString ename;
  7145. if( scope != "" && scope != "::" )
  7146. ename = scope + "::";
  7147. else
  7148. ename = scope;
  7149. ename += name;
  7150. asCString str;
  7151. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  7152. Error(str, errNode);
  7153. // Declare the variable now so that it will not be reported again
  7154. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  7155. // Mark the variable as initialized so that the user will not be bother by it again
  7156. sVariable *v = variables->GetVariable(name.AddressOf());
  7157. asASSERT(v);
  7158. if( v ) v->isInitialized = true;
  7159. }
  7160. // Return -1 to signal that the variable wasn't found
  7161. return -1;
  7162. }
  7163. return 0;
  7164. }
  7165. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  7166. {
  7167. // Shouldn't receive any byte code
  7168. asASSERT(ctx->bc.GetLastInstr() == -1);
  7169. asCScriptNode *vnode = node->firstChild;
  7170. ctx->exprNode = vnode;
  7171. if( vnode->nodeType == snVariableAccess )
  7172. {
  7173. // Determine the scope resolution of the variable
  7174. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  7175. // Determine the name of the variable
  7176. asASSERT(vnode->nodeType == snIdentifier );
  7177. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  7178. return CompileVariableAccess(name, scope, ctx, node);
  7179. }
  7180. else if( vnode->nodeType == snConstant )
  7181. {
  7182. if( vnode->tokenType == ttIntConstant )
  7183. {
  7184. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7185. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  7186. // Do we need 64 bits?
  7187. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  7188. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  7189. if( val>>31 )
  7190. {
  7191. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  7192. if( val>>63 )
  7193. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7194. else
  7195. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  7196. }
  7197. else
  7198. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  7199. }
  7200. else if( vnode->tokenType == ttBitsConstant )
  7201. {
  7202. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7203. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  7204. // TODO: Check for overflow
  7205. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
  7206. // Do we need 64 bits?
  7207. if( val>>32 )
  7208. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7209. else
  7210. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  7211. }
  7212. else if( vnode->tokenType == ttFloatConstant )
  7213. {
  7214. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7215. // TODO: Check for overflow
  7216. size_t numScanned;
  7217. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  7218. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  7219. #ifndef AS_USE_DOUBLE_AS_FLOAT
  7220. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  7221. asASSERT(numScanned == vnode->tokenLength - 1);
  7222. #endif
  7223. }
  7224. else if( vnode->tokenType == ttDoubleConstant )
  7225. {
  7226. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7227. // TODO: Check for overflow
  7228. size_t numScanned;
  7229. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  7230. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  7231. asASSERT(numScanned == vnode->tokenLength);
  7232. }
  7233. else if( vnode->tokenType == ttTrue ||
  7234. vnode->tokenType == ttFalse )
  7235. {
  7236. #if AS_SIZEOF_BOOL == 1
  7237. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7238. #else
  7239. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7240. #endif
  7241. }
  7242. else if( vnode->tokenType == ttStringConstant ||
  7243. vnode->tokenType == ttMultilineStringConstant ||
  7244. vnode->tokenType == ttHeredocStringConstant )
  7245. {
  7246. asCString str;
  7247. asCScriptNode *snode = vnode->firstChild;
  7248. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  7249. {
  7250. // Treat the single quoted string as a single character literal
  7251. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7252. asDWORD val = 0;
  7253. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  7254. {
  7255. // This is the start of a UTF8 encoded character. We need to decode it
  7256. val = asStringDecodeUTF8(str.AddressOf(), 0);
  7257. if( val == (asDWORD)-1 )
  7258. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7259. }
  7260. else
  7261. {
  7262. val = ProcessStringConstant(str, snode);
  7263. if( val == (asDWORD)-1 )
  7264. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7265. }
  7266. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  7267. }
  7268. else
  7269. {
  7270. // Process the string constants
  7271. while( snode )
  7272. {
  7273. asCString cat;
  7274. if( snode->tokenType == ttStringConstant )
  7275. {
  7276. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7277. ProcessStringConstant(cat, snode);
  7278. }
  7279. else if( snode->tokenType == ttMultilineStringConstant )
  7280. {
  7281. if( !engine->ep.allowMultilineStrings )
  7282. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  7283. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7284. ProcessStringConstant(cat, snode);
  7285. }
  7286. else if( snode->tokenType == ttHeredocStringConstant )
  7287. {
  7288. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  7289. ProcessHeredocStringConstant(cat, snode);
  7290. }
  7291. str += cat;
  7292. snode = snode->next;
  7293. }
  7294. // Call the string factory function to create a string object
  7295. asCScriptFunction *descr = engine->stringFactory;
  7296. if( descr == 0 )
  7297. {
  7298. // Error
  7299. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  7300. // Give dummy value
  7301. ctx->type.SetDummy();
  7302. return -1;
  7303. }
  7304. else
  7305. {
  7306. // Register the constant string with the engine
  7307. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  7308. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  7309. bool useVariable = false;
  7310. int stackOffset = 0;
  7311. if( descr->DoesReturnOnStack() )
  7312. {
  7313. useVariable = true;
  7314. stackOffset = AllocateVariable(descr->returnType, true);
  7315. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  7316. }
  7317. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  7318. }
  7319. }
  7320. }
  7321. else if( vnode->tokenType == ttNull )
  7322. {
  7323. ctx->bc.Instr(asBC_PshNull);
  7324. ctx->type.SetNullConstant();
  7325. }
  7326. else
  7327. asASSERT(false);
  7328. }
  7329. else if( vnode->nodeType == snFunctionCall )
  7330. {
  7331. // Determine the scope resolution
  7332. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  7333. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  7334. }
  7335. else if( vnode->nodeType == snConstructCall )
  7336. {
  7337. CompileConstructCall(vnode, ctx);
  7338. }
  7339. else if( vnode->nodeType == snAssignment )
  7340. {
  7341. asSExprContext e(engine);
  7342. int r = CompileAssignment(vnode, &e);
  7343. if( r < 0 )
  7344. {
  7345. ctx->type.SetDummy();
  7346. return r;
  7347. }
  7348. MergeExprBytecodeAndType(ctx, &e);
  7349. }
  7350. else if( vnode->nodeType == snCast )
  7351. {
  7352. // Implement the cast operator
  7353. CompileConversion(vnode, ctx);
  7354. }
  7355. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  7356. {
  7357. // This is a void expression
  7358. ctx->type.SetVoidExpression();
  7359. }
  7360. else
  7361. asASSERT(false);
  7362. return 0;
  7363. }
  7364. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  7365. {
  7366. int charLiteral = -1;
  7367. // Process escape sequences
  7368. asCArray<char> str((int)cstr.GetLength());
  7369. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  7370. {
  7371. #ifdef AS_DOUBLEBYTE_CHARSET
  7372. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  7373. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  7374. {
  7375. // This is the lead character of a double byte character
  7376. // include the trail character without checking it's value.
  7377. str.PushLast(cstr[n]);
  7378. n++;
  7379. str.PushLast(cstr[n]);
  7380. continue;
  7381. }
  7382. #endif
  7383. asUINT val;
  7384. if( processEscapeSequences && cstr[n] == '\\' )
  7385. {
  7386. ++n;
  7387. if( n == cstr.GetLength() )
  7388. {
  7389. if( charLiteral == -1 ) charLiteral = 0;
  7390. return charLiteral;
  7391. }
  7392. // Hexadecimal escape sequences will allow the construction of
  7393. // invalid unicode sequences, but the string should also work as
  7394. // a bytearray so we must support this. The code for working with
  7395. // unicode text must be prepared to handle invalid unicode sequences
  7396. if( cstr[n] == 'x' || cstr[n] == 'X' )
  7397. {
  7398. ++n;
  7399. if( n == cstr.GetLength() ) break;
  7400. val = 0;
  7401. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  7402. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  7403. {
  7404. if( cstr[n] >= '0' && cstr[n] <= '9' )
  7405. val = val*16 + cstr[n] - '0';
  7406. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  7407. val = val*16 + cstr[n] - 'a' + 10;
  7408. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  7409. val = val*16 + cstr[n] - 'A' + 10;
  7410. else
  7411. break;
  7412. }
  7413. // Rewind one, since the loop will increment it again
  7414. n--;
  7415. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  7416. if( engine->ep.stringEncoding == 0 )
  7417. {
  7418. str.PushLast((asBYTE)val);
  7419. }
  7420. else
  7421. {
  7422. #ifndef AS_BIG_ENDIAN
  7423. str.PushLast((asBYTE)val);
  7424. str.PushLast((asBYTE)(val>>8));
  7425. #else
  7426. str.PushLast((asBYTE)(val>>8));
  7427. str.PushLast((asBYTE)val);
  7428. #endif
  7429. }
  7430. if( charLiteral == -1 ) charLiteral = val;
  7431. continue;
  7432. }
  7433. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  7434. {
  7435. // \u expects 4 hex digits
  7436. // \U expects 8 hex digits
  7437. bool expect2 = cstr[n] == 'u';
  7438. int c = expect2 ? 4 : 8;
  7439. val = 0;
  7440. for( ; c > 0; c-- )
  7441. {
  7442. ++n;
  7443. if( n == cstr.GetLength() ) break;
  7444. if( cstr[n] >= '0' && cstr[n] <= '9' )
  7445. val = val*16 + cstr[n] - '0';
  7446. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  7447. val = val*16 + cstr[n] - 'a' + 10;
  7448. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  7449. val = val*16 + cstr[n] - 'A' + 10;
  7450. else
  7451. break;
  7452. }
  7453. if( c != 0 )
  7454. {
  7455. // Give warning about invalid code point
  7456. // TODO: Need code position for warning
  7457. asCString msg;
  7458. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  7459. Warning(msg, node);
  7460. continue;
  7461. }
  7462. }
  7463. else
  7464. {
  7465. if( cstr[n] == '"' )
  7466. val = '"';
  7467. else if( cstr[n] == '\'' )
  7468. val = '\'';
  7469. else if( cstr[n] == 'n' )
  7470. val = '\n';
  7471. else if( cstr[n] == 'r' )
  7472. val = '\r';
  7473. else if( cstr[n] == 't' )
  7474. val = '\t';
  7475. else if( cstr[n] == '0' )
  7476. val = '\0';
  7477. else if( cstr[n] == '\\' )
  7478. val = '\\';
  7479. else
  7480. {
  7481. // Invalid escape sequence
  7482. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  7483. continue;
  7484. }
  7485. }
  7486. }
  7487. else
  7488. {
  7489. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  7490. {
  7491. unsigned int len;
  7492. val = asStringDecodeUTF8(&cstr[n], &len);
  7493. if( val == 0xFFFFFFFF )
  7494. {
  7495. // Incorrect UTF8 encoding. Use only the first byte
  7496. // TODO: Need code position for warning
  7497. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  7498. val = (unsigned char)cstr[n];
  7499. }
  7500. else
  7501. n += len-1;
  7502. }
  7503. else
  7504. val = (unsigned char)cstr[n];
  7505. }
  7506. // Add the character to the final string
  7507. char encodedValue[5];
  7508. int len;
  7509. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  7510. {
  7511. // Convert to UTF8 encoded
  7512. len = asStringEncodeUTF8(val, encodedValue);
  7513. }
  7514. else if( engine->ep.stringEncoding == 1 )
  7515. {
  7516. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  7517. len = asStringEncodeUTF16(val, encodedValue);
  7518. }
  7519. else
  7520. {
  7521. // Do not convert ASCII characters
  7522. encodedValue[0] = (asBYTE)val;
  7523. len = 1;
  7524. }
  7525. if( len < 0 )
  7526. {
  7527. // Give warning about invalid code point
  7528. // TODO: Need code position for warning
  7529. Warning(TXT_INVALID_UNICODE_VALUE, node);
  7530. }
  7531. else
  7532. {
  7533. // Add the encoded value to the final string
  7534. str.Concatenate(encodedValue, len);
  7535. if( charLiteral == -1 ) charLiteral = val;
  7536. }
  7537. }
  7538. cstr.Assign(str.AddressOf(), str.GetLength());
  7539. return charLiteral;
  7540. }
  7541. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  7542. {
  7543. // Remove first line if it only contains whitespace
  7544. int start;
  7545. for( start = 0; start < (int)str.GetLength(); start++ )
  7546. {
  7547. if( str[start] == '\n' )
  7548. {
  7549. // Remove the linebreak as well
  7550. start++;
  7551. break;
  7552. }
  7553. if( str[start] != ' ' &&
  7554. str[start] != '\t' &&
  7555. str[start] != '\r' )
  7556. {
  7557. // Don't remove anything
  7558. start = 0;
  7559. break;
  7560. }
  7561. }
  7562. // Remove the line after the last line break if it only contains whitespaces
  7563. int end;
  7564. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  7565. {
  7566. if( str[end] == '\n' )
  7567. {
  7568. // Don't remove the last line break
  7569. end++;
  7570. break;
  7571. }
  7572. if( str[end] != ' ' &&
  7573. str[end] != '\t' &&
  7574. str[end] != '\r' )
  7575. {
  7576. // Don't remove anything
  7577. end = (int)str.GetLength();
  7578. break;
  7579. }
  7580. }
  7581. if( end < 0 ) end = 0;
  7582. asCString tmp;
  7583. if( end > start )
  7584. tmp.Assign(&str[start], end-start);
  7585. ProcessStringConstant(tmp, node, false);
  7586. str = tmp;
  7587. }
  7588. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  7589. {
  7590. asSExprContext expr(engine);
  7591. asCDataType to;
  7592. bool anyErrors = false;
  7593. EImplicitConv convType;
  7594. if( node->nodeType == snConstructCall )
  7595. {
  7596. convType = asIC_EXPLICIT_VAL_CAST;
  7597. // Verify that there is only one argument
  7598. if( node->lastChild->firstChild == 0 ||
  7599. node->lastChild->firstChild != node->lastChild->lastChild )
  7600. {
  7601. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  7602. expr.type.SetDummy();
  7603. anyErrors = true;
  7604. }
  7605. else
  7606. {
  7607. // Compile the expression
  7608. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  7609. if( r < 0 )
  7610. anyErrors = true;
  7611. }
  7612. // Determine the requested type
  7613. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7614. to.MakeReadOnly(true); // Default to const
  7615. asASSERT(to.IsPrimitive());
  7616. }
  7617. else
  7618. {
  7619. convType = asIC_EXPLICIT_REF_CAST;
  7620. // Compile the expression
  7621. int r = CompileAssignment(node->lastChild, &expr);
  7622. if( r < 0 )
  7623. anyErrors = true;
  7624. // Determine the requested type
  7625. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7626. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  7627. // If the type support object handles, then use it
  7628. if( to.SupportHandles() )
  7629. {
  7630. to.MakeHandle(true);
  7631. }
  7632. else if( !to.IsObjectHandle() )
  7633. {
  7634. // The cast<type> operator can only be used for reference casts
  7635. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  7636. anyErrors = true;
  7637. }
  7638. }
  7639. // Do not allow casting to non shared type if we're compiling a shared method
  7640. if( outFunc->IsShared() &&
  7641. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  7642. {
  7643. asCString msg;
  7644. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  7645. Error(msg, node);
  7646. anyErrors = true;
  7647. }
  7648. if( anyErrors )
  7649. {
  7650. // Assume that the error can be fixed and allow the compilation to continue
  7651. ctx->type.SetConstantDW(to, 0);
  7652. return;
  7653. }
  7654. ProcessPropertyGetAccessor(&expr, node);
  7655. // Don't allow any operators on expressions that take address of class method
  7656. if( expr.IsClassMethod() )
  7657. {
  7658. Error(TXT_INVALID_OP_ON_METHOD, node);
  7659. return;
  7660. }
  7661. // We don't want a reference for conversion casts
  7662. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  7663. {
  7664. if( expr.type.dataType.IsObject() )
  7665. Dereference(&expr, true);
  7666. else
  7667. ConvertToVariable(&expr);
  7668. }
  7669. ImplicitConversion(&expr, to, node, convType);
  7670. IsVariableInitialized(&expr.type, node);
  7671. // If no type conversion is really tried ignore it
  7672. if( to == expr.type.dataType )
  7673. {
  7674. // This will keep information about constant type
  7675. MergeExprBytecode(ctx, &expr);
  7676. ctx->type = expr.type;
  7677. return;
  7678. }
  7679. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  7680. {
  7681. MergeExprBytecode(ctx, &expr);
  7682. ctx->type = expr.type;
  7683. ctx->type.dataType.MakeReadOnly(true);
  7684. return;
  7685. }
  7686. // The implicit conversion already does most of the conversions permitted,
  7687. // here we'll only treat those conversions that require an explicit cast.
  7688. bool conversionOK = false;
  7689. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  7690. {
  7691. if( !expr.type.dataType.IsObject() )
  7692. ConvertToTempVariable(&expr);
  7693. if( to.IsObjectHandle() &&
  7694. expr.type.dataType.IsObjectHandle() &&
  7695. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  7696. {
  7697. conversionOK = CompileRefCast(&expr, to, true, node);
  7698. MergeExprBytecode(ctx, &expr);
  7699. ctx->type = expr.type;
  7700. }
  7701. }
  7702. if( conversionOK )
  7703. return;
  7704. // Conversion not available
  7705. ctx->type.SetDummy();
  7706. asCString strTo, strFrom;
  7707. strTo = to.Format();
  7708. strFrom = expr.type.dataType.Format();
  7709. asCString msg;
  7710. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  7711. Error(msg, node);
  7712. }
  7713. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  7714. {
  7715. // deferAll is set to true if for example the function returns a reference, since in
  7716. // this case the function might be returning a reference to one of the arguments.
  7717. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  7718. // Parameters that are sent by reference should be assigned
  7719. // to the evaluated expression if it is an lvalue
  7720. // Evaluate the arguments from last to first
  7721. int n = (int)descr->parameterTypes.GetLength() - 1;
  7722. for( ; n >= 0; n-- )
  7723. {
  7724. // All &out arguments must be deferred
  7725. // If deferAll is set all objects passed by reference or handle must be deferred
  7726. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  7727. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  7728. {
  7729. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  7730. // For &inout, only store the argument if it is for a temporary variable
  7731. if( engine->ep.allowUnsafeReferences ||
  7732. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  7733. {
  7734. // Store the argument for later processing
  7735. asSDeferredParam outParam;
  7736. outParam.argNode = args[n]->exprNode;
  7737. outParam.argType = args[n]->type;
  7738. outParam.argInOutFlags = descr->inOutFlags[n];
  7739. outParam.origExpr = args[n]->origExpr;
  7740. ctx->deferredParams.PushLast(outParam);
  7741. }
  7742. }
  7743. else
  7744. {
  7745. // Release the temporary variable now
  7746. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  7747. }
  7748. // Move the argument's deferred expressions over to the final expression
  7749. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  7750. {
  7751. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  7752. args[n]->deferredParams[m].origExpr = 0;
  7753. }
  7754. args[n]->deferredParams.SetLength(0);
  7755. }
  7756. }
  7757. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  7758. {
  7759. if( isProcessingDeferredParams ) return;
  7760. isProcessingDeferredParams = true;
  7761. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  7762. {
  7763. asSDeferredParam outParam = ctx->deferredParams[n];
  7764. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  7765. {
  7766. // Just release the variable
  7767. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7768. }
  7769. else if( outParam.argInOutFlags == asTM_OUTREF )
  7770. {
  7771. asSExprContext *expr = outParam.origExpr;
  7772. outParam.origExpr = 0;
  7773. if( outParam.argType.dataType.IsObjectHandle() )
  7774. {
  7775. // Implicitly convert the value to a handle
  7776. if( expr->type.dataType.IsObjectHandle() )
  7777. expr->type.isExplicitHandle = true;
  7778. }
  7779. // Verify that the expression result in a lvalue, or a property accessor
  7780. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  7781. {
  7782. asSExprContext rctx(engine);
  7783. rctx.type = outParam.argType;
  7784. if( rctx.type.dataType.IsPrimitive() )
  7785. rctx.type.dataType.MakeReference(false);
  7786. else
  7787. {
  7788. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  7789. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  7790. if( expr->type.isExplicitHandle )
  7791. rctx.type.isExplicitHandle = true;
  7792. }
  7793. asSExprContext o(engine);
  7794. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  7795. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  7796. // The assignment may itself have resulted in a new temporary variable, e.g. if
  7797. // the opAssign returns a non-reference. We must release this temporary variable
  7798. // since it won't be used
  7799. ReleaseTemporaryVariable(o.type, &o.bc);
  7800. MergeExprBytecode(ctx, &o);
  7801. }
  7802. else
  7803. {
  7804. // We must still evaluate the expression
  7805. MergeExprBytecode(ctx, expr);
  7806. if( !expr->type.IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  7807. ctx->bc.Instr(asBC_PopPtr);
  7808. // Give a warning, except if the argument is void, null or 0 which indicate the argument is really to be ignored
  7809. if( !expr->type.IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  7810. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  7811. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7812. }
  7813. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  7814. // Delete the original expression context
  7815. asDELETE(expr,asSExprContext);
  7816. }
  7817. else // &inout
  7818. {
  7819. if( outParam.argType.isTemporary )
  7820. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7821. else if( !outParam.argType.isVariable )
  7822. {
  7823. if( outParam.argType.dataType.IsObject() &&
  7824. ((outParam.argType.dataType.GetBehaviour()->addref &&
  7825. outParam.argType.dataType.GetBehaviour()->release) ||
  7826. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  7827. {
  7828. // Release the object handle that was taken to guarantee the reference
  7829. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7830. }
  7831. }
  7832. }
  7833. }
  7834. ctx->deferredParams.SetLength(0);
  7835. isProcessingDeferredParams = false;
  7836. }
  7837. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  7838. {
  7839. // The first node is a datatype node
  7840. asCString name;
  7841. asCTypeInfo tempObj;
  7842. bool onHeap = true;
  7843. asCArray<int> funcs;
  7844. // It is possible that the name is really a constructor
  7845. asCDataType dt;
  7846. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7847. if( dt.IsPrimitive() )
  7848. {
  7849. // This is a cast to a primitive type
  7850. CompileConversion(node, ctx);
  7851. return;
  7852. }
  7853. if( !dt.CanBeInstantiated() )
  7854. {
  7855. asCString str;
  7856. if( dt.IsAbstractClass() )
  7857. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf());
  7858. else if( dt.IsInterface() )
  7859. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format().AddressOf());
  7860. else
  7861. // TODO: Improve error message to explain why
  7862. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format().AddressOf());
  7863. Error(str, node);
  7864. ctx->type.SetDummy();
  7865. return;
  7866. }
  7867. // Do not allow constructing non-shared types in shared functions
  7868. if( outFunc->IsShared() &&
  7869. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  7870. {
  7871. asCString msg;
  7872. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  7873. Error(msg, node);
  7874. }
  7875. // Compile the arguments
  7876. asCArray<asSExprContext *> args;
  7877. asCArray<asSNamedArgument> namedArgs;
  7878. asCArray<asCTypeInfo> temporaryVariables;
  7879. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  7880. {
  7881. // Check for a value cast behaviour
  7882. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  7883. {
  7884. asSExprContext conv(engine);
  7885. conv.type = args[0]->type;
  7886. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  7887. // Don't use this if the cost is 0 because it would mean that nothing
  7888. // is done and the scipt wants a new value to be constructed
  7889. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  7890. {
  7891. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  7892. ctx->bc.AddCode(&args[0]->bc);
  7893. ctx->type = args[0]->type;
  7894. asDELETE(args[0],asSExprContext);
  7895. return;
  7896. }
  7897. }
  7898. // Check for possible constructor/factory
  7899. name = dt.Format();
  7900. asSTypeBehaviour *beh = dt.GetBehaviour();
  7901. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7902. {
  7903. funcs = beh->constructors;
  7904. // Value types and script types are allocated through the constructor
  7905. tempObj.dataType = dt;
  7906. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  7907. tempObj.dataType.MakeReference(true);
  7908. tempObj.isTemporary = true;
  7909. tempObj.isVariable = true;
  7910. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  7911. // Push the address of the object on the stack
  7912. if( onHeap )
  7913. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  7914. }
  7915. else
  7916. funcs = beh->factories;
  7917. // Special case: Allow calling func(void) with a void expression.
  7918. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  7919. {
  7920. // Evaluate the expression before the function call
  7921. MergeExprBytecode(ctx, args[0]);
  7922. asDELETE(args[0],asSExprContext);
  7923. args.SetLength(0);
  7924. }
  7925. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  7926. // If none has been registered, just allocate the variable and push it on the stack.
  7927. if( args.GetLength() == 0 )
  7928. {
  7929. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  7930. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  7931. {
  7932. // Call the default constructor
  7933. ctx->type = tempObj;
  7934. if( onHeap )
  7935. {
  7936. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  7937. ctx->bc.RemoveLastInstr();
  7938. }
  7939. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  7940. // Push the reference on the stack
  7941. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7942. return;
  7943. }
  7944. }
  7945. // Special case: If this is a construction of a delegate and the expression names an object method
  7946. if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
  7947. {
  7948. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  7949. // case no object delegate will be created, but instead a delegate for a function pointer
  7950. // In theory a simple cast would be good in this case, but this is a construct call so it
  7951. // is expected that a new object is created.
  7952. dt.MakeHandle(true);
  7953. ctx->type.Set(dt);
  7954. // The delegate must be able to hold on to a reference to the object
  7955. if( !args[0]->type.dataType.SupportHandles() )
  7956. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  7957. else
  7958. {
  7959. // Filter the available object methods to find the one that matches the func def
  7960. asCObjectType *type = args[0]->type.dataType.GetObjectType();
  7961. asCScriptFunction *bestMethod = 0;
  7962. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  7963. {
  7964. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  7965. if( func->name != args[0]->methodName )
  7966. continue;
  7967. // If the expression is for a const object, then only const methods should be accepted
  7968. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  7969. continue;
  7970. if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
  7971. {
  7972. bestMethod = func;
  7973. // If the expression is non-const the non-const overloaded method has priority
  7974. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  7975. break;
  7976. }
  7977. }
  7978. if( bestMethod )
  7979. {
  7980. // The object pointer is already on the stack
  7981. MergeExprBytecode(ctx, args[0]);
  7982. // Push the function pointer as an additional argument
  7983. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  7984. // Call the factory function for the delegate
  7985. asCArray<int> funcs;
  7986. builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
  7987. asASSERT( funcs.GetLength() == 1 );
  7988. ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
  7989. // Store the returned delegate in a temporary variable
  7990. int returnOffset = AllocateVariable(dt, true, false);
  7991. dt.MakeReference(true);
  7992. ctx->type.SetVariable(dt, returnOffset, true);
  7993. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  7994. // Push a reference to the temporary variable on the stack
  7995. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  7996. }
  7997. else
  7998. {
  7999. asCString msg;
  8000. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
  8001. Error(msg.AddressOf(), node);
  8002. }
  8003. }
  8004. // Clean-up arg
  8005. asDELETE(args[0],asSExprContext);
  8006. return;
  8007. }
  8008. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  8009. if( funcs.GetLength() != 1 )
  8010. {
  8011. // The error was reported by MatchFunctions()
  8012. // Dummy value
  8013. ctx->type.SetDummy();
  8014. }
  8015. else
  8016. {
  8017. // TODO: Clean up: Merge this with MakeFunctionCall
  8018. // Add the default values for arguments not explicitly supplied
  8019. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], dt.GetObjectType(), &namedArgs);
  8020. if( r == asSUCCESS )
  8021. {
  8022. asCByteCode objBC(engine);
  8023. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  8024. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  8025. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  8026. {
  8027. // If the object is allocated on the stack, then call the constructor as a normal function
  8028. if( onHeap )
  8029. {
  8030. int offset = 0;
  8031. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  8032. for( asUINT n = 0; n < args.GetLength(); n++ )
  8033. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  8034. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  8035. }
  8036. else
  8037. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8038. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  8039. // Add tag that the object has been initialized
  8040. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  8041. // The constructor doesn't return anything,
  8042. // so we have to manually inform the type of
  8043. // the return value
  8044. ctx->type = tempObj;
  8045. if( !onHeap )
  8046. ctx->type.dataType.MakeReference(false);
  8047. // Push the address of the object on the stack again
  8048. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8049. }
  8050. else
  8051. {
  8052. // Call the factory to create the reference type
  8053. PerformFunctionCall(funcs[0], ctx, false, &args);
  8054. }
  8055. }
  8056. }
  8057. }
  8058. else
  8059. {
  8060. // Failed to compile the argument list, set the result to the dummy type
  8061. ctx->type.SetDummy();
  8062. }
  8063. // Cleanup
  8064. for( asUINT n = 0; n < args.GetLength(); n++ )
  8065. if( args[n] )
  8066. {
  8067. asDELETE(args[n],asSExprContext);
  8068. }
  8069. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  8070. if( namedArgs[n].ctx )
  8071. {
  8072. asDELETE(namedArgs[n].ctx,asSExprContext);
  8073. }
  8074. }
  8075. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  8076. {
  8077. asCTypeInfo tempObj;
  8078. asCArray<int> funcs;
  8079. int localVar = -1;
  8080. bool initializeMembers = false;
  8081. asSExprContext funcExpr(engine);
  8082. asCScriptNode *nm = node->lastChild->prev;
  8083. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  8084. // First check for a local variable as it would take precedence
  8085. // Must not allow function names, nor global variables to be returned in this instance
  8086. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  8087. if( objectType == 0 )
  8088. {
  8089. localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true);
  8090. if( localVar >= 0 &&
  8091. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8092. funcExpr.methodName == "" )
  8093. {
  8094. // The variable is not a function or object with opCall
  8095. asCString msg;
  8096. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8097. Error(msg, node);
  8098. return -1;
  8099. }
  8100. // If the name matches a method name, then reset the indicator that nothing was found
  8101. if( funcExpr.methodName != "" )
  8102. localVar = -1;
  8103. }
  8104. if( localVar < 0 )
  8105. {
  8106. // If this is an expression post op, or if a class method is
  8107. // being compiled, then we should look for matching class methods
  8108. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  8109. {
  8110. // If we're compiling a constructor and the name of the function is super then
  8111. // the constructor of the base class is being called.
  8112. // super cannot be prefixed with a scope operator
  8113. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  8114. {
  8115. // If the class is not derived from anyone else, calling super should give an error
  8116. if( outFunc && outFunc->objectType->derivedFrom )
  8117. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  8118. // Must not allow calling base class' constructor multiple times
  8119. if( continueLabels.GetLength() > 0 )
  8120. {
  8121. // If a continue label is set we are in a loop
  8122. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  8123. }
  8124. else if( breakLabels.GetLength() > 0 )
  8125. {
  8126. // TODO: inheritance: Should eventually allow constructors in switch statements
  8127. // If a break label is set we are either in a loop or a switch statements
  8128. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  8129. }
  8130. else if( m_isConstructorCalled )
  8131. {
  8132. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  8133. }
  8134. m_isConstructorCalled = true;
  8135. // We need to initialize the class members, but only after all the deferred arguments have been completed
  8136. initializeMembers = true;
  8137. }
  8138. else
  8139. {
  8140. // The scope is can be used to specify the base class
  8141. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope);
  8142. }
  8143. // It is still possible that there is a class member of a function type or a type with opCall methods
  8144. if( funcs.GetLength() == 0 )
  8145. {
  8146. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType);
  8147. if( r >= 0 &&
  8148. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8149. funcExpr.methodName == "" )
  8150. {
  8151. // The variable is not a function
  8152. asCString msg;
  8153. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8154. Error(msg, node);
  8155. return -1;
  8156. }
  8157. // If the name is an access property, make sure the original value isn't
  8158. // dereferenced when calling the access property as part a dot post operator
  8159. if( objectType && (funcExpr.property_get || funcExpr.property_set) && !ctx->type.dataType.IsReference() )
  8160. funcExpr.property_ref = false;
  8161. }
  8162. // If a class method is being called implicitly, then add the this pointer for the call
  8163. if( funcs.GetLength() && !objectType )
  8164. {
  8165. objectType = outFunc->objectType;
  8166. asCDataType dt = asCDataType::CreateObject(objectType, false);
  8167. // The object pointer is located at stack position 0
  8168. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8169. ctx->type.SetVariable(dt, 0, false);
  8170. ctx->type.dataType.MakeReference(true);
  8171. Dereference(ctx, true);
  8172. }
  8173. }
  8174. // If it is not a class method or member function pointer,
  8175. // then look for global functions or global function pointers,
  8176. // unless this is an expression post op, incase only member
  8177. // functions are expected
  8178. if( objectType == 0 && funcs.GetLength() == 0 && (funcExpr.type.dataType.GetFuncDef() == 0 || funcExpr.type.dataType.IsObject()) )
  8179. {
  8180. // The scope is used to define the namespace
  8181. asSNameSpace *ns = DetermineNameSpace(scope);
  8182. if( ns )
  8183. {
  8184. // Search recursively in parent namespaces
  8185. while( ns && funcs.GetLength() == 0 && funcExpr.type.dataType.GetFuncDef() == 0 )
  8186. {
  8187. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8188. if( funcs.GetLength() == 0 )
  8189. {
  8190. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true);
  8191. if( r >= 0 &&
  8192. !(funcExpr.type.dataType.GetFuncDef() || funcExpr.type.dataType.IsObject()) &&
  8193. funcExpr.methodName == "" )
  8194. {
  8195. // The variable is not a function
  8196. asCString msg;
  8197. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8198. Error(msg, node);
  8199. return -1;
  8200. }
  8201. }
  8202. ns = builder->GetParentNameSpace(ns);
  8203. }
  8204. }
  8205. else
  8206. {
  8207. asCString msg;
  8208. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  8209. Error(msg, node);
  8210. return -1;
  8211. }
  8212. }
  8213. }
  8214. if( funcs.GetLength() == 0 )
  8215. {
  8216. if( funcExpr.type.dataType.GetFuncDef() )
  8217. {
  8218. funcs.PushLast(funcExpr.type.dataType.GetFuncDef()->id);
  8219. }
  8220. else if( funcExpr.type.dataType.IsObject() )
  8221. {
  8222. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  8223. if( ctx->type.isTemporary )
  8224. {
  8225. asASSERT( objectType );
  8226. asSDeferredParam deferred;
  8227. deferred.origExpr = 0;
  8228. deferred.argInOutFlags = asTM_INREF;
  8229. deferred.argNode = 0;
  8230. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8231. ctx->deferredParams.PushLast(deferred);
  8232. }
  8233. if( funcExpr.property_get == 0 )
  8234. Dereference(ctx, true);
  8235. // Add the bytecode for accessing the object on which opCall will be called
  8236. MergeExprBytecodeAndType(ctx, &funcExpr);
  8237. ProcessPropertyGetAccessor(ctx, node);
  8238. Dereference(ctx, true);
  8239. objectType = funcExpr.type.dataType.GetObjectType();
  8240. // Get the opCall methods from the object type
  8241. if( funcExpr.type.dataType.IsObjectHandle() )
  8242. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  8243. else
  8244. objIsConst = funcExpr.type.dataType.IsReadOnly();
  8245. builder->GetObjectMethodDescriptions("opCall", funcExpr.type.dataType.GetObjectType(), funcs, objIsConst);
  8246. }
  8247. }
  8248. // Compile the arguments
  8249. asCArray<asSExprContext *> args;
  8250. asCArray<asSNamedArgument> namedArgs;
  8251. bool isOK = true;
  8252. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  8253. {
  8254. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  8255. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) && !args[0]->type.IsVoidExpression() )
  8256. {
  8257. // Evaluate the expression before the function call
  8258. MergeExprBytecode(ctx, args[0]);
  8259. asDELETE(args[0],asSExprContext);
  8260. args.SetLength(0);
  8261. }
  8262. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  8263. if( funcs.GetLength() != 1 )
  8264. {
  8265. // The error was reported by MatchFunctions()
  8266. // Dummy value
  8267. ctx->type.SetDummy();
  8268. isOK = false;
  8269. }
  8270. else
  8271. {
  8272. // Add the default values for arguments not explicitly supplied
  8273. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  8274. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8275. // is it enough to make sure it is in a local variable?
  8276. // For function pointer we must guarantee that the function is safe, i.e.
  8277. // by first storing the function pointer in a local variable (if it isn't already in one)
  8278. if( r == asSUCCESS )
  8279. {
  8280. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  8281. if( func->funcType == asFUNC_FUNCDEF )
  8282. {
  8283. if( objectType && funcExpr.property_get <= 0 )
  8284. {
  8285. Dereference(ctx, true); // Dereference the object pointer to access the member
  8286. // The actual function should be called as if a global function
  8287. objectType = 0;
  8288. }
  8289. if( funcExpr.property_get > 0 )
  8290. {
  8291. ProcessPropertyGetAccessor(&funcExpr, node);
  8292. Dereference(&funcExpr, true);
  8293. }
  8294. else
  8295. {
  8296. Dereference(&funcExpr, true);
  8297. ConvertToVariable(&funcExpr);
  8298. }
  8299. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  8300. funcExpr.bc.Instr(asBC_PopPtr);
  8301. asCTypeInfo tmp = ctx->type;
  8302. MergeExprBytecodeAndType(ctx, &funcExpr);
  8303. ReleaseTemporaryVariable(tmp, &ctx->bc);
  8304. }
  8305. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  8306. }
  8307. else
  8308. isOK = false;
  8309. }
  8310. }
  8311. else
  8312. {
  8313. // Failed to compile the argument list, set the dummy type and continue compilation
  8314. ctx->type.SetDummy();
  8315. isOK = false;
  8316. }
  8317. // Cleanup
  8318. for( asUINT n = 0; n < args.GetLength(); n++ )
  8319. if( args[n] )
  8320. {
  8321. asDELETE(args[n],asSExprContext);
  8322. }
  8323. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  8324. if( namedArgs[n].ctx )
  8325. {
  8326. asDELETE(namedArgs[n].ctx,asSExprContext);
  8327. }
  8328. if( initializeMembers )
  8329. {
  8330. asASSERT( m_isConstructor );
  8331. // Need to initialize members here, as they may use the properties of the base class
  8332. // If there are multiple paths that call super(), then there will also be multiple
  8333. // locations with initializations of the members. It is not possible to consolidate
  8334. // these in one place, as the expressions for the initialization are evaluated where
  8335. // they are compiled, which means that they may access different variables depending
  8336. // on the scope where super() is called.
  8337. // Members that don't have an explicit initialization expression will be initialized
  8338. // beginning of the constructor as they are guaranteed not to use at the any
  8339. // members of the base class.
  8340. CompileMemberInitialization(&ctx->bc, false);
  8341. }
  8342. return isOK ? 0 : -1;
  8343. }
  8344. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  8345. {
  8346. asSNameSpace *ns;
  8347. if( scope == "" )
  8348. {
  8349. if( outFunc->nameSpace->name != "" )
  8350. ns = outFunc->nameSpace;
  8351. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  8352. ns = outFunc->objectType->nameSpace;
  8353. else
  8354. ns = engine->nameSpaces[0];
  8355. }
  8356. else if( scope == "::" )
  8357. ns = engine->nameSpaces[0];
  8358. else
  8359. ns = engine->FindNameSpace(scope.AddressOf());
  8360. return ns;
  8361. }
  8362. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  8363. {
  8364. int op = node->tokenType;
  8365. // Don't allow any prefix operators except handle on expressions that take address of class method
  8366. if( ctx->IsClassMethod() && op != ttHandle )
  8367. {
  8368. Error(TXT_INVALID_OP_ON_METHOD, node);
  8369. return -1;
  8370. }
  8371. // Don't allow any operators on void expressions
  8372. if( ctx->type.IsVoidExpression() )
  8373. {
  8374. Error(TXT_VOID_CANT_BE_OPERAND, node);
  8375. return -1;
  8376. }
  8377. IsVariableInitialized(&ctx->type, node);
  8378. if( op == ttHandle )
  8379. {
  8380. if( ctx->methodName != "" )
  8381. {
  8382. // Don't allow taking the handle of a handle
  8383. if( ctx->type.isExplicitHandle )
  8384. {
  8385. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8386. return -1;
  8387. }
  8388. }
  8389. else
  8390. {
  8391. // Don't allow taking handle of a handle, i.e. @@
  8392. if( ctx->type.isExplicitHandle )
  8393. {
  8394. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8395. return -1;
  8396. }
  8397. // @null is allowed even though it is implicit
  8398. if( !ctx->type.IsNullConstant() )
  8399. {
  8400. // Verify that the type allow its handle to be taken
  8401. if( !ctx->type.dataType.IsObject() ||
  8402. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  8403. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  8404. {
  8405. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  8406. return -1;
  8407. }
  8408. // Objects that are not local variables are not references
  8409. // Objects allocated on the stack are also not marked as references
  8410. if( !ctx->type.dataType.IsReference() &&
  8411. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  8412. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  8413. {
  8414. Error(TXT_NOT_VALID_REFERENCE, node);
  8415. return -1;
  8416. }
  8417. // Convert the expression to a handle
  8418. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  8419. {
  8420. asCDataType to = ctx->type.dataType;
  8421. to.MakeHandle(true);
  8422. to.MakeReference(true);
  8423. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  8424. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  8425. asASSERT( ctx->type.dataType.IsObjectHandle() );
  8426. }
  8427. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  8428. {
  8429. // For the ASHANDLE type we'll simply set the expression as a handle
  8430. ctx->type.dataType.MakeHandle(true);
  8431. }
  8432. }
  8433. }
  8434. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  8435. ctx->type.isExplicitHandle = true;
  8436. }
  8437. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  8438. {
  8439. // Look for the appropriate method
  8440. // There is no overloadable operator for unary plus
  8441. const char *opName = 0;
  8442. switch( op )
  8443. {
  8444. case ttMinus: opName = "opNeg"; break;
  8445. case ttBitNot: opName = "opCom"; break;
  8446. case ttInc: opName = "opPreInc"; break;
  8447. case ttDec: opName = "opPreDec"; break;
  8448. }
  8449. if( opName )
  8450. {
  8451. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  8452. ProcessPropertyGetAccessor(ctx, node);
  8453. // 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
  8454. // Find the correct method
  8455. bool isConst = ctx->type.dataType.IsObjectConst();
  8456. asCArray<int> funcs;
  8457. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8458. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8459. {
  8460. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8461. if( func->name == opName &&
  8462. func->parameterTypes.GetLength() == 0 &&
  8463. (!isConst || func->isReadOnly) )
  8464. {
  8465. funcs.PushLast(func->id);
  8466. }
  8467. }
  8468. // Did we find the method?
  8469. if( funcs.GetLength() == 1 )
  8470. {
  8471. asCArray<asSExprContext *> args;
  8472. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  8473. return 0;
  8474. }
  8475. else if( funcs.GetLength() == 0 )
  8476. {
  8477. asCString str;
  8478. str = asCString(opName) + "()";
  8479. if( isConst )
  8480. str += " const";
  8481. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  8482. Error(str, node);
  8483. ctx->type.SetDummy();
  8484. return -1;
  8485. }
  8486. else if( funcs.GetLength() > 1 )
  8487. {
  8488. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8489. PrintMatchingFuncs(funcs, node);
  8490. ctx->type.SetDummy();
  8491. return -1;
  8492. }
  8493. }
  8494. else if( op == ttPlus )
  8495. {
  8496. Error(TXT_ILLEGAL_OPERATION, node);
  8497. ctx->type.SetDummy();
  8498. return -1;
  8499. }
  8500. }
  8501. else if( op == ttPlus || op == ttMinus )
  8502. {
  8503. // This is only for primitives. Objects are treated in the above block
  8504. // Make sure the type is a math type
  8505. if( !(ctx->type.dataType.IsIntegerType() ||
  8506. ctx->type.dataType.IsUnsignedType() ||
  8507. ctx->type.dataType.IsFloatType() ||
  8508. ctx->type.dataType.IsDoubleType() ) )
  8509. {
  8510. Error(TXT_ILLEGAL_OPERATION, node);
  8511. return -1;
  8512. }
  8513. ProcessPropertyGetAccessor(ctx, node);
  8514. asCDataType to = ctx->type.dataType;
  8515. if( ctx->type.dataType.IsUnsignedType() )
  8516. {
  8517. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8518. to = asCDataType::CreatePrimitive(ttInt8, false);
  8519. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8520. to = asCDataType::CreatePrimitive(ttInt16, false);
  8521. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8522. to = asCDataType::CreatePrimitive(ttInt, false);
  8523. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  8524. to = asCDataType::CreatePrimitive(ttInt64, false);
  8525. else
  8526. {
  8527. Error(TXT_INVALID_TYPE, node);
  8528. return -1;
  8529. }
  8530. }
  8531. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  8532. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  8533. if( !ctx->type.isConstant )
  8534. {
  8535. ConvertToTempVariable(ctx);
  8536. asASSERT(!ctx->type.isLValue);
  8537. if( op == ttMinus )
  8538. {
  8539. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8540. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  8541. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8542. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  8543. else if( ctx->type.dataType.IsFloatType() )
  8544. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  8545. else if( ctx->type.dataType.IsDoubleType() )
  8546. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  8547. else
  8548. {
  8549. Error(TXT_ILLEGAL_OPERATION, node);
  8550. return -1;
  8551. }
  8552. return 0;
  8553. }
  8554. }
  8555. else
  8556. {
  8557. if( op == ttMinus )
  8558. {
  8559. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8560. ctx->type.intValue = -ctx->type.intValue;
  8561. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8562. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  8563. else if( ctx->type.dataType.IsFloatType() )
  8564. ctx->type.floatValue = -ctx->type.floatValue;
  8565. else if( ctx->type.dataType.IsDoubleType() )
  8566. ctx->type.doubleValue = -ctx->type.doubleValue;
  8567. else
  8568. {
  8569. Error(TXT_ILLEGAL_OPERATION, node);
  8570. return -1;
  8571. }
  8572. return 0;
  8573. }
  8574. }
  8575. }
  8576. else if( op == ttNot )
  8577. {
  8578. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  8579. {
  8580. if( ctx->type.isConstant )
  8581. {
  8582. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8583. return 0;
  8584. }
  8585. ProcessPropertyGetAccessor(ctx, node);
  8586. ConvertToTempVariable(ctx);
  8587. asASSERT(!ctx->type.isLValue);
  8588. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  8589. }
  8590. else
  8591. {
  8592. Error(TXT_ILLEGAL_OPERATION, node);
  8593. return -1;
  8594. }
  8595. }
  8596. else if( op == ttBitNot )
  8597. {
  8598. ProcessPropertyGetAccessor(ctx, node);
  8599. asCDataType to = ctx->type.dataType;
  8600. if( ctx->type.dataType.IsIntegerType() )
  8601. {
  8602. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8603. to = asCDataType::CreatePrimitive(ttUInt8, false);
  8604. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8605. to = asCDataType::CreatePrimitive(ttUInt16, false);
  8606. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8607. to = asCDataType::CreatePrimitive(ttUInt, false);
  8608. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  8609. to = asCDataType::CreatePrimitive(ttUInt64, false);
  8610. else
  8611. {
  8612. Error(TXT_INVALID_TYPE, node);
  8613. return -1;
  8614. }
  8615. }
  8616. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  8617. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  8618. if( ctx->type.dataType.IsUnsignedType() )
  8619. {
  8620. if( ctx->type.isConstant )
  8621. {
  8622. ctx->type.qwordValue = ~ctx->type.qwordValue;
  8623. return 0;
  8624. }
  8625. ConvertToTempVariable(ctx);
  8626. asASSERT(!ctx->type.isLValue);
  8627. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8628. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  8629. else
  8630. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  8631. }
  8632. else
  8633. {
  8634. Error(TXT_ILLEGAL_OPERATION, node);
  8635. return -1;
  8636. }
  8637. }
  8638. else if( op == ttInc || op == ttDec )
  8639. {
  8640. // Need a reference to the primitive that will be updated
  8641. // The result of this expression is the same reference as before
  8642. // Make sure the reference isn't a temporary variable
  8643. if( ctx->type.isTemporary )
  8644. {
  8645. Error(TXT_REF_IS_TEMP, node);
  8646. return -1;
  8647. }
  8648. if( ctx->type.dataType.IsReadOnly() )
  8649. {
  8650. Error(TXT_REF_IS_READ_ONLY, node);
  8651. return -1;
  8652. }
  8653. if( ctx->property_get || ctx->property_set )
  8654. {
  8655. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  8656. return -1;
  8657. }
  8658. if( !ctx->type.isLValue )
  8659. {
  8660. Error(TXT_NOT_LVALUE, node);
  8661. return -1;
  8662. }
  8663. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8664. ConvertToReference(ctx);
  8665. else if( !ctx->type.dataType.IsReference() )
  8666. {
  8667. Error(TXT_NOT_VALID_REFERENCE, node);
  8668. return -1;
  8669. }
  8670. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  8671. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  8672. {
  8673. if( op == ttInc )
  8674. ctx->bc.Instr(asBC_INCi64);
  8675. else
  8676. ctx->bc.Instr(asBC_DECi64);
  8677. }
  8678. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  8679. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  8680. {
  8681. if( op == ttInc )
  8682. ctx->bc.Instr(asBC_INCi);
  8683. else
  8684. ctx->bc.Instr(asBC_DECi);
  8685. }
  8686. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  8687. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  8688. {
  8689. if( op == ttInc )
  8690. ctx->bc.Instr(asBC_INCi16);
  8691. else
  8692. ctx->bc.Instr(asBC_DECi16);
  8693. }
  8694. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  8695. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  8696. {
  8697. if( op == ttInc )
  8698. ctx->bc.Instr(asBC_INCi8);
  8699. else
  8700. ctx->bc.Instr(asBC_DECi8);
  8701. }
  8702. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  8703. {
  8704. if( op == ttInc )
  8705. ctx->bc.Instr(asBC_INCf);
  8706. else
  8707. ctx->bc.Instr(asBC_DECf);
  8708. }
  8709. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  8710. {
  8711. if( op == ttInc )
  8712. ctx->bc.Instr(asBC_INCd);
  8713. else
  8714. ctx->bc.Instr(asBC_DECd);
  8715. }
  8716. else
  8717. {
  8718. Error(TXT_ILLEGAL_OPERATION, node);
  8719. return -1;
  8720. }
  8721. }
  8722. else
  8723. {
  8724. // Unknown operator
  8725. asASSERT(false);
  8726. return -1;
  8727. }
  8728. return 0;
  8729. }
  8730. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  8731. {
  8732. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8733. {
  8734. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  8735. ctx->type.dataType.MakeReference(true);
  8736. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  8737. }
  8738. }
  8739. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  8740. {
  8741. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  8742. }
  8743. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  8744. {
  8745. if( engine->ep.propertyAccessorMode == 0 )
  8746. {
  8747. // Property accessors have been disabled by the application
  8748. return 0;
  8749. }
  8750. int getId = 0, setId = 0;
  8751. asCString getName = "get_" + name;
  8752. asCString setName = "set_" + name;
  8753. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  8754. if( ctx->type.dataType.IsObject() )
  8755. {
  8756. asASSERT( ns == 0 );
  8757. // Don't look for property accessors in script classes if the script
  8758. // property accessors have been disabled by the application
  8759. if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
  8760. engine->ep.propertyAccessorMode == 2 )
  8761. {
  8762. // Check if the object has any methods with the corresponding accessor name(s)
  8763. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8764. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8765. {
  8766. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8767. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  8768. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  8769. {
  8770. if( getId == 0 )
  8771. getId = ot->methods[n];
  8772. else
  8773. {
  8774. if( multipleGetFuncs.GetLength() == 0 )
  8775. multipleGetFuncs.PushLast(getId);
  8776. multipleGetFuncs.PushLast(ot->methods[n]);
  8777. }
  8778. }
  8779. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  8780. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  8781. {
  8782. if( setId == 0 )
  8783. setId = ot->methods[n];
  8784. else
  8785. {
  8786. if( multipleSetFuncs.GetLength() == 0 )
  8787. multipleSetFuncs.PushLast(setId);
  8788. multipleSetFuncs.PushLast(ot->methods[n]);
  8789. }
  8790. }
  8791. }
  8792. }
  8793. }
  8794. else
  8795. {
  8796. asASSERT( ns != 0 );
  8797. // Look for appropriate global functions.
  8798. asCArray<int> funcs;
  8799. asUINT n;
  8800. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  8801. for( n = 0; n < funcs.GetLength(); n++ )
  8802. {
  8803. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  8804. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  8805. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  8806. {
  8807. if( getId == 0 )
  8808. getId = funcs[n];
  8809. else
  8810. {
  8811. if( multipleGetFuncs.GetLength() == 0 )
  8812. multipleGetFuncs.PushLast(getId);
  8813. multipleGetFuncs.PushLast(funcs[n]);
  8814. }
  8815. }
  8816. }
  8817. funcs.SetLength(0);
  8818. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  8819. for( n = 0; n < funcs.GetLength(); n++ )
  8820. {
  8821. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  8822. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  8823. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  8824. {
  8825. if( setId == 0 )
  8826. setId = funcs[n];
  8827. else
  8828. {
  8829. if( multipleSetFuncs.GetLength() == 0 )
  8830. multipleSetFuncs.PushLast(getId);
  8831. multipleSetFuncs.PushLast(funcs[n]);
  8832. }
  8833. }
  8834. }
  8835. }
  8836. bool isConst = ctx->type.dataType.IsObjectConst();
  8837. // Check for multiple matches
  8838. if( multipleGetFuncs.GetLength() > 0 )
  8839. {
  8840. // Filter the list by constness
  8841. FilterConst(multipleGetFuncs, !isConst);
  8842. if( multipleGetFuncs.GetLength() > 1 )
  8843. {
  8844. asCString str;
  8845. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  8846. Error(str, node);
  8847. PrintMatchingFuncs(multipleGetFuncs, node);
  8848. return -1;
  8849. }
  8850. else
  8851. {
  8852. // The id may have changed
  8853. getId = multipleGetFuncs[0];
  8854. }
  8855. }
  8856. if( multipleSetFuncs.GetLength() > 0 )
  8857. {
  8858. // Filter the list by constness
  8859. FilterConst(multipleSetFuncs, !isConst);
  8860. if( multipleSetFuncs.GetLength() > 1 )
  8861. {
  8862. asCString str;
  8863. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  8864. Error(str, node);
  8865. PrintMatchingFuncs(multipleSetFuncs, node);
  8866. return -1;
  8867. }
  8868. else
  8869. {
  8870. // The id may have changed
  8871. setId = multipleSetFuncs[0];
  8872. }
  8873. }
  8874. // Check for type compatibility between get and set accessor
  8875. if( getId && setId )
  8876. {
  8877. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  8878. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  8879. // It is permitted for a getter to return a handle and the setter to take a reference
  8880. int idx = (arg?1:0);
  8881. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  8882. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  8883. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  8884. {
  8885. asCString str;
  8886. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  8887. Error(str, node);
  8888. asCArray<int> funcs;
  8889. funcs.PushLast(getId);
  8890. funcs.PushLast(setId);
  8891. PrintMatchingFuncs(funcs, node);
  8892. return -1;
  8893. }
  8894. }
  8895. // Check if we are within one of the accessors
  8896. int realGetId = getId;
  8897. int realSetId = setId;
  8898. if( outFunc->objectType && isThisAccess )
  8899. {
  8900. // The property accessors would be virtual functions, so we need to find the real implementation
  8901. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  8902. if( getFunc &&
  8903. getFunc->funcType == asFUNC_VIRTUAL &&
  8904. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  8905. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  8906. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  8907. if( setFunc &&
  8908. setFunc->funcType == asFUNC_VIRTUAL &&
  8909. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  8910. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  8911. }
  8912. // Avoid recursive call, by not treating this as a property accessor call.
  8913. // This will also allow having the real property with the same name as the accessors.
  8914. if( (isThisAccess || outFunc->objectType == 0) &&
  8915. ((realGetId && realGetId == outFunc->id) ||
  8916. (realSetId && realSetId == outFunc->id)) )
  8917. {
  8918. getId = 0;
  8919. setId = 0;
  8920. }
  8921. // Check if the application has disabled script written property accessors
  8922. if( engine->ep.propertyAccessorMode == 1 )
  8923. {
  8924. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  8925. getId = 0;
  8926. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  8927. setId = 0;
  8928. }
  8929. if( getId || setId )
  8930. {
  8931. // Property accessors were found, but we don't know which is to be used yet, so
  8932. // we just prepare the bytecode for the method call, and then store the function ids
  8933. // so that the right one can be used when we get there.
  8934. ctx->property_get = getId;
  8935. ctx->property_set = setId;
  8936. if( ctx->type.dataType.IsObject() )
  8937. {
  8938. // If the object is read-only then we need to remember that
  8939. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  8940. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  8941. ctx->property_const = true;
  8942. else
  8943. ctx->property_const = false;
  8944. // If the object is a handle then we need to remember that
  8945. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  8946. ctx->property_ref = ctx->type.dataType.IsReference();
  8947. }
  8948. // The setter's parameter type is used as the property type,
  8949. // unless only the getter is available
  8950. asCDataType dt;
  8951. if( setId )
  8952. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  8953. else
  8954. dt = builder->GetFunctionDescription(getId)->returnType;
  8955. // Just change the type, the context must still maintain information
  8956. // about previous variable offset and the indicator of temporary variable.
  8957. int offset = ctx->type.stackOffset;
  8958. bool isTemp = ctx->type.isTemporary;
  8959. ctx->type.Set(dt);
  8960. ctx->type.stackOffset = (short)offset;
  8961. ctx->type.isTemporary = isTemp;
  8962. ctx->exprNode = node;
  8963. // Store the argument for later use
  8964. if( arg )
  8965. {
  8966. ctx->property_arg = asNEW(asSExprContext)(engine);
  8967. if( ctx->property_arg == 0 )
  8968. {
  8969. // Out of memory
  8970. return -1;
  8971. }
  8972. MergeExprBytecodeAndType(ctx->property_arg, arg);
  8973. }
  8974. return 1;
  8975. }
  8976. // No accessor was found
  8977. return 0;
  8978. }
  8979. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  8980. {
  8981. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  8982. if( !ctx->property_set )
  8983. {
  8984. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  8985. return -1;
  8986. }
  8987. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  8988. // Make sure the arg match the property
  8989. asCArray<int> funcs;
  8990. funcs.PushLast(ctx->property_set);
  8991. asCArray<asSExprContext *> args;
  8992. if( ctx->property_arg )
  8993. args.PushLast(ctx->property_arg);
  8994. args.PushLast(arg);
  8995. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  8996. if( funcs.GetLength() == 0 )
  8997. {
  8998. // MatchFunctions already reported the error
  8999. if( ctx->property_arg )
  9000. {
  9001. asDELETE(ctx->property_arg, asSExprContext);
  9002. ctx->property_arg = 0;
  9003. }
  9004. return -1;
  9005. }
  9006. if( func->objectType )
  9007. {
  9008. // Setup the context with the original type so the method call gets built correctly
  9009. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9010. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9011. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9012. // Don't allow the call if the object is read-only and the property accessor is not const
  9013. if( ctx->property_const && !func->isReadOnly )
  9014. {
  9015. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9016. asCArray<int> funcs;
  9017. funcs.PushLast(ctx->property_set);
  9018. PrintMatchingFuncs(funcs, node);
  9019. }
  9020. }
  9021. // Call the accessor
  9022. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  9023. ctx->property_get = 0;
  9024. ctx->property_set = 0;
  9025. if( ctx->property_arg )
  9026. {
  9027. asDELETE(ctx->property_arg, asSExprContext);
  9028. ctx->property_arg = 0;
  9029. }
  9030. return 0;
  9031. }
  9032. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  9033. {
  9034. // If no property accessor has been prepared then don't do anything
  9035. if( !ctx->property_get && !ctx->property_set )
  9036. return;
  9037. if( !ctx->property_get )
  9038. {
  9039. // Raise error on missing accessor
  9040. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  9041. ctx->type.SetDummy();
  9042. return;
  9043. }
  9044. asCTypeInfo objType = ctx->type;
  9045. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  9046. // Make sure the arg match the property
  9047. asCArray<int> funcs;
  9048. funcs.PushLast(ctx->property_get);
  9049. asCArray<asSExprContext *> args;
  9050. if( ctx->property_arg )
  9051. args.PushLast(ctx->property_arg);
  9052. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  9053. if( funcs.GetLength() == 0 )
  9054. {
  9055. // MatchFunctions already reported the error
  9056. if( ctx->property_arg )
  9057. {
  9058. asDELETE(ctx->property_arg, asSExprContext);
  9059. ctx->property_arg = 0;
  9060. }
  9061. ctx->type.SetDummy();
  9062. return;
  9063. }
  9064. if( func->objectType )
  9065. {
  9066. // Setup the context with the original type so the method call gets built correctly
  9067. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9068. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9069. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9070. // Don't allow the call if the object is read-only and the property accessor is not const
  9071. if( ctx->property_const && !func->isReadOnly )
  9072. {
  9073. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9074. asCArray<int> funcs;
  9075. funcs.PushLast(ctx->property_get);
  9076. PrintMatchingFuncs(funcs, node);
  9077. }
  9078. }
  9079. // Call the accessor
  9080. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  9081. ctx->property_get = 0;
  9082. ctx->property_set = 0;
  9083. if( ctx->property_arg )
  9084. {
  9085. asDELETE(ctx->property_arg, asSExprContext);
  9086. ctx->property_arg = 0;
  9087. }
  9088. }
  9089. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  9090. {
  9091. // Don't allow any postfix operators on expressions that take address of class method
  9092. if( ctx->IsClassMethod() )
  9093. {
  9094. Error(TXT_INVALID_OP_ON_METHOD, node);
  9095. return -1;
  9096. }
  9097. // Don't allow any operators on void expressions
  9098. if( ctx->type.IsVoidExpression() )
  9099. {
  9100. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9101. return -1;
  9102. }
  9103. // Check if the variable is initialized (if it indeed is a variable)
  9104. IsVariableInitialized(&ctx->type, node);
  9105. int op = node->tokenType;
  9106. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9107. {
  9108. const char *opName = 0;
  9109. switch( op )
  9110. {
  9111. case ttInc: opName = "opPostInc"; break;
  9112. case ttDec: opName = "opPostDec"; break;
  9113. }
  9114. if( opName )
  9115. {
  9116. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9117. ProcessPropertyGetAccessor(ctx, node);
  9118. // 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
  9119. // Find the correct method
  9120. bool isConst = ctx->type.dataType.IsObjectConst();
  9121. asCArray<int> funcs;
  9122. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  9123. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9124. {
  9125. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9126. if( func->name == opName &&
  9127. func->parameterTypes.GetLength() == 0 &&
  9128. (!isConst || func->isReadOnly) )
  9129. {
  9130. funcs.PushLast(func->id);
  9131. }
  9132. }
  9133. // Did we find the method?
  9134. if( funcs.GetLength() == 1 )
  9135. {
  9136. asCArray<asSExprContext *> args;
  9137. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.GetObjectType(), args, node);
  9138. return 0;
  9139. }
  9140. else if( funcs.GetLength() == 0 )
  9141. {
  9142. asCString str;
  9143. str = asCString(opName) + "()";
  9144. if( isConst )
  9145. str += " const";
  9146. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9147. Error(str, node);
  9148. ctx->type.SetDummy();
  9149. return -1;
  9150. }
  9151. else if( funcs.GetLength() > 1 )
  9152. {
  9153. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9154. PrintMatchingFuncs(funcs, node);
  9155. ctx->type.SetDummy();
  9156. return -1;
  9157. }
  9158. }
  9159. }
  9160. else if( op == ttInc || op == ttDec )
  9161. {
  9162. // Make sure the reference isn't a temporary variable
  9163. if( ctx->type.isTemporary )
  9164. {
  9165. Error(TXT_REF_IS_TEMP, node);
  9166. return -1;
  9167. }
  9168. if( ctx->type.dataType.IsReadOnly() )
  9169. {
  9170. Error(TXT_REF_IS_READ_ONLY, node);
  9171. return -1;
  9172. }
  9173. if( ctx->property_get || ctx->property_set )
  9174. {
  9175. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  9176. return -1;
  9177. }
  9178. if( !ctx->type.isLValue )
  9179. {
  9180. Error(TXT_NOT_LVALUE, node);
  9181. return -1;
  9182. }
  9183. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9184. ConvertToReference(ctx);
  9185. else if( !ctx->type.dataType.IsReference() )
  9186. {
  9187. Error(TXT_NOT_VALID_REFERENCE, node);
  9188. return -1;
  9189. }
  9190. // Copy the value to a temp before changing it
  9191. ConvertToTempVariable(ctx);
  9192. asASSERT(!ctx->type.isLValue);
  9193. // Increment the value pointed to by the reference still in the register
  9194. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  9195. if( ctx->type.dataType.IsDoubleType() )
  9196. {
  9197. iInc = asBC_INCd;
  9198. iDec = asBC_DECd;
  9199. }
  9200. else if( ctx->type.dataType.IsFloatType() )
  9201. {
  9202. iInc = asBC_INCf;
  9203. iDec = asBC_DECf;
  9204. }
  9205. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  9206. {
  9207. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  9208. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  9209. {
  9210. iInc = asBC_INCi16;
  9211. iDec = asBC_DECi16;
  9212. }
  9213. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  9214. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  9215. {
  9216. iInc = asBC_INCi8;
  9217. iDec = asBC_DECi8;
  9218. }
  9219. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  9220. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  9221. {
  9222. iInc = asBC_INCi64;
  9223. iDec = asBC_DECi64;
  9224. }
  9225. }
  9226. else
  9227. {
  9228. Error(TXT_ILLEGAL_OPERATION, node);
  9229. return -1;
  9230. }
  9231. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  9232. }
  9233. else if( op == ttDot )
  9234. {
  9235. if( node->firstChild->nodeType == snIdentifier )
  9236. {
  9237. ProcessPropertyGetAccessor(ctx, node);
  9238. // Get the property name
  9239. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  9240. if( ctx->type.dataType.IsObject() )
  9241. {
  9242. // We need to look for get/set property accessors.
  9243. // If found, the context stores information on the get/set accessors
  9244. // until it is known which is to be used.
  9245. int r = 0;
  9246. if( node->next && node->next->tokenType == ttOpenBracket )
  9247. {
  9248. // The property accessor should take an index arg
  9249. asSExprContext dummyArg(engine);
  9250. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  9251. }
  9252. if( r == 0 )
  9253. r = FindPropertyAccessor(name, ctx, node, 0);
  9254. if( r != 0 )
  9255. return r;
  9256. if( !ctx->type.dataType.IsPrimitive() )
  9257. Dereference(ctx, true);
  9258. if( ctx->type.dataType.IsObjectHandle() )
  9259. {
  9260. // Convert the handle to a normal object
  9261. asCDataType dt = ctx->type.dataType;
  9262. dt.MakeHandle(false);
  9263. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  9264. // The handle may not have been an lvalue, but the dereferenced object is
  9265. ctx->type.isLValue = true;
  9266. }
  9267. bool isConst = ctx->type.dataType.IsObjectConst();
  9268. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  9269. if( prop )
  9270. {
  9271. // Is the property access allowed?
  9272. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  9273. {
  9274. asCString msg;
  9275. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  9276. Error(msg, node);
  9277. }
  9278. // Put the offset on the stack
  9279. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  9280. if( prop->type.IsReference() )
  9281. ctx->bc.Instr(asBC_RDSPtr);
  9282. // Reference to primitive must be stored in the temp register
  9283. if( prop->type.IsPrimitive() )
  9284. {
  9285. ctx->bc.Instr(asBC_PopRPtr);
  9286. }
  9287. // Keep information about temporary variables as deferred expression
  9288. if( ctx->type.isTemporary )
  9289. {
  9290. // Add the release of this reference, as a deferred expression
  9291. asSDeferredParam deferred;
  9292. deferred.origExpr = 0;
  9293. deferred.argInOutFlags = asTM_INREF;
  9294. deferred.argNode = 0;
  9295. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9296. ctx->deferredParams.PushLast(deferred);
  9297. }
  9298. // Set the new type and make sure it is not treated as a variable anymore
  9299. ctx->type.dataType = prop->type;
  9300. ctx->type.dataType.MakeReference(true);
  9301. ctx->type.isVariable = false;
  9302. ctx->type.isTemporary = false;
  9303. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  9304. {
  9305. // Objects that are members are not references
  9306. ctx->type.dataType.MakeReference(false);
  9307. }
  9308. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  9309. }
  9310. else
  9311. {
  9312. // If the name is not a property, the compiler must check if the name matches
  9313. // a method, which can be used for constructing delegates
  9314. asIScriptFunction *func = 0;
  9315. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  9316. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9317. {
  9318. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  9319. {
  9320. func = engine->scriptFunctions[ot->methods[n]];
  9321. break;
  9322. }
  9323. }
  9324. if( func )
  9325. {
  9326. // An object method was found. Keep the name of the method in the expression, but
  9327. // don't actually modify the bytecode at this point since it is not yet known what
  9328. // the method will be used for, or even what overloaded method should be used.
  9329. ctx->methodName = name;
  9330. }
  9331. else
  9332. {
  9333. asCString str;
  9334. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  9335. Error(str, node);
  9336. return -1;
  9337. }
  9338. }
  9339. }
  9340. else
  9341. {
  9342. asCString str;
  9343. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  9344. Error(str, node);
  9345. return -1;
  9346. }
  9347. }
  9348. else
  9349. {
  9350. // Make sure it is an object we are accessing
  9351. if( !ctx->type.dataType.IsObject() )
  9352. {
  9353. asCString str;
  9354. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  9355. Error(str, node);
  9356. return -1;
  9357. }
  9358. // Process the get property accessor
  9359. ProcessPropertyGetAccessor(ctx, node);
  9360. // Compile function call
  9361. int r = CompileFunctionCall(node->firstChild, ctx, ctx->type.dataType.GetObjectType(), ctx->type.dataType.IsObjectConst());
  9362. if( r < 0 ) return r;
  9363. }
  9364. }
  9365. else if( op == ttOpenBracket )
  9366. {
  9367. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  9368. // then we should use that instead of processing it now. If the argument has already been
  9369. // evaluated, then we should process the property accessor as a get access now as the new
  9370. // index operator is on the result of that accessor.
  9371. asCString propertyName;
  9372. asSNameSpace *ns = 0;
  9373. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  9374. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  9375. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  9376. {
  9377. // Determine the name of the property accessor
  9378. asCScriptFunction *func = 0;
  9379. if( ctx->property_get )
  9380. func = builder->GetFunctionDescription(ctx->property_get);
  9381. else
  9382. func = builder->GetFunctionDescription(ctx->property_set);
  9383. propertyName = func->GetName();
  9384. propertyName = propertyName.SubString(4);
  9385. // Set the original type of the expression so we can re-evaluate the property accessor
  9386. if( func->objectType )
  9387. {
  9388. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  9389. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9390. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9391. }
  9392. else
  9393. {
  9394. // Store the namespace where the function is declared
  9395. // so the same function can be found later
  9396. ctx->type.SetDummy();
  9397. ns = func->nameSpace;
  9398. }
  9399. ctx->property_get = ctx->property_set = 0;
  9400. if( ctx->property_arg )
  9401. {
  9402. asDELETE(ctx->property_arg, asSExprContext);
  9403. ctx->property_arg = 0;
  9404. }
  9405. }
  9406. else
  9407. {
  9408. if( !ctx->type.dataType.IsObject() )
  9409. {
  9410. asCString str;
  9411. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  9412. Error(str, node);
  9413. return -1;
  9414. }
  9415. ProcessPropertyGetAccessor(ctx, node);
  9416. }
  9417. // Compile the expression
  9418. bool isOK = true;
  9419. asCArray<asSExprContext *> args;
  9420. asCArray<asSNamedArgument> namedArgs;
  9421. asASSERT( node->firstChild->nodeType == snArgList );
  9422. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  9423. {
  9424. // Check for the existence of the opIndex method
  9425. bool lookForProperty = true;
  9426. if( propertyName == "" )
  9427. {
  9428. bool isConst = ctx->type.dataType.IsObjectConst();
  9429. asCObjectType *objectType = ctx->type.dataType.GetObjectType();
  9430. asCArray<int> funcs;
  9431. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  9432. if( funcs.GetLength() > 0 )
  9433. {
  9434. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  9435. lookForProperty = false;
  9436. // Determine which of opIndex methods that match
  9437. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  9438. if( funcs.GetLength() != 1 )
  9439. {
  9440. // The error has already been reported by MatchFunctions
  9441. isOK = false;
  9442. }
  9443. else
  9444. {
  9445. // Add the default values for arguments not explicitly supplied
  9446. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  9447. if( r == 0 )
  9448. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset);
  9449. else
  9450. isOK = false;
  9451. }
  9452. }
  9453. }
  9454. if( lookForProperty && isOK )
  9455. {
  9456. if( args.GetLength() != 1 )
  9457. {
  9458. // TODO: opIndex: Implement this
  9459. Error("Property accessor with index only support 1 index argument for now", node);
  9460. isOK = false;
  9461. }
  9462. Dereference(ctx, true);
  9463. asSExprContext lctx(engine);
  9464. MergeExprBytecodeAndType(&lctx, ctx);
  9465. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  9466. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  9467. if( r == 0 )
  9468. {
  9469. asCString str;
  9470. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  9471. Error(str, node);
  9472. isOK = false;
  9473. }
  9474. else if( r < 0 )
  9475. isOK = false;
  9476. if( isOK )
  9477. MergeExprBytecodeAndType(ctx, &lctx);
  9478. }
  9479. }
  9480. else
  9481. isOK = false;
  9482. // Cleanup
  9483. for( asUINT n = 0; n < args.GetLength(); n++ )
  9484. if( args[n] )
  9485. {
  9486. asDELETE(args[n],asSExprContext);
  9487. }
  9488. if( !isOK )
  9489. return -1;
  9490. }
  9491. else if( op == ttOpenParanthesis )
  9492. {
  9493. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  9494. // Make sure the expression is a funcdef or an object that may have opCall methods
  9495. if( !ctx->type.dataType.GetFuncDef() && !ctx->type.dataType.IsObject() )
  9496. {
  9497. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  9498. return -1;
  9499. }
  9500. // Compile arguments
  9501. asCArray<asSExprContext *> args;
  9502. asCArray<asSNamedArgument> namedArgs;
  9503. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9504. {
  9505. // Match arguments with the funcdef
  9506. asCArray<int> funcs;
  9507. if( ctx->type.dataType.GetFuncDef() )
  9508. {
  9509. funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
  9510. MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf(), &namedArgs);
  9511. }
  9512. else
  9513. {
  9514. bool isConst = ctx->type.dataType.IsObjectConst();
  9515. builder->GetObjectMethodDescriptions("opCall", ctx->type.dataType.GetObjectType(), funcs, isConst);
  9516. MatchFunctions(funcs, args, node, "opCall", &namedArgs, ctx->type.dataType.GetObjectType(), isConst);
  9517. }
  9518. if( funcs.GetLength() != 1 )
  9519. {
  9520. // The error was reported by MatchFunctions()
  9521. // Dummy value
  9522. ctx->type.SetDummy();
  9523. }
  9524. else
  9525. {
  9526. // Add the default values for arguments not explicitly supplied
  9527. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], ctx->type.dataType.GetObjectType(), &namedArgs);
  9528. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9529. // is it enough to make sure it is in a local variable?
  9530. // For function pointer we must guarantee that the function is safe, i.e.
  9531. // by first storing the function pointer in a local variable (if it isn't already in one)
  9532. if( r == asSUCCESS )
  9533. {
  9534. Dereference(ctx, true);
  9535. if( ctx->type.dataType.GetFuncDef() )
  9536. {
  9537. if( !ctx->type.isVariable )
  9538. ConvertToVariable(ctx);
  9539. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  9540. ctx->bc.Instr(asBC_PopPtr);
  9541. }
  9542. MakeFunctionCall(ctx, funcs[0], 0, args, node, false, 0, ctx->type.stackOffset);
  9543. }
  9544. }
  9545. }
  9546. else
  9547. ctx->type.SetDummy();
  9548. // Cleanup
  9549. for( asUINT n = 0; n < args.GetLength(); n++ )
  9550. if( args[n] )
  9551. {
  9552. asDELETE(args[n],asSExprContext);
  9553. }
  9554. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9555. if( namedArgs[n].ctx )
  9556. {
  9557. asDELETE(namedArgs[n].ctx,asSExprContext);
  9558. }
  9559. }
  9560. return 0;
  9561. }
  9562. int asCCompiler::GetPrecedence(asCScriptNode *op)
  9563. {
  9564. // x ** y
  9565. // x * y, x / y, x % y
  9566. // x + y, x - y
  9567. // x <= y, x < y, x >= y, x > y
  9568. // x = =y, x != y, x xor y, x is y, x !is y
  9569. // x and y
  9570. // x or y
  9571. // The following are not used in this function,
  9572. // but should have lower precedence than the above
  9573. // x ? y : z
  9574. // x = y
  9575. // The expression term have the highest precedence
  9576. if( op->nodeType == snExprTerm )
  9577. return 1;
  9578. // Evaluate operators by token
  9579. int tokenType = op->tokenType;
  9580. if( tokenType == ttStarStar )
  9581. return 0;
  9582. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  9583. return -1;
  9584. if( tokenType == ttPlus || tokenType == ttMinus )
  9585. return -2;
  9586. if( tokenType == ttBitShiftLeft ||
  9587. tokenType == ttBitShiftRight ||
  9588. tokenType == ttBitShiftRightArith )
  9589. return -3;
  9590. if( tokenType == ttAmp )
  9591. return -4;
  9592. if( tokenType == ttBitXor )
  9593. return -5;
  9594. if( tokenType == ttBitOr )
  9595. return -6;
  9596. if( tokenType == ttLessThanOrEqual ||
  9597. tokenType == ttLessThan ||
  9598. tokenType == ttGreaterThanOrEqual ||
  9599. tokenType == ttGreaterThan )
  9600. return -7;
  9601. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  9602. return -8;
  9603. if( tokenType == ttAnd )
  9604. return -9;
  9605. if( tokenType == ttOr )
  9606. return -10;
  9607. // Unknown operator
  9608. asASSERT(false);
  9609. return 0;
  9610. }
  9611. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  9612. {
  9613. matches.SetLength(0);
  9614. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  9615. {
  9616. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  9617. // Does the function have arguments enough?
  9618. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  9619. continue;
  9620. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  9621. if( cost != -1 )
  9622. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  9623. }
  9624. return (asUINT)matches.GetLength();
  9625. }
  9626. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  9627. {
  9628. // void expressions can match any out parameter, but nothing else
  9629. if( argExpr->type.IsVoidExpression() )
  9630. {
  9631. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  9632. return 0;
  9633. return -1;
  9634. }
  9635. // Can we make the match by implicit conversion?
  9636. asSExprContext ti(engine);
  9637. ti.type = argExpr->type;
  9638. ti.methodName = argExpr->methodName;
  9639. ti.enumValue = argExpr->enumValue;
  9640. if( argExpr->type.dataType.IsPrimitive() )
  9641. ti.type.dataType.MakeReference(false);
  9642. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  9643. // If the function parameter is an inout-reference then it must not be possible to call the
  9644. // function with an incorrect argument type, even though the type can normally be converted.
  9645. if( desc->parameterTypes[paramNum].IsReference() &&
  9646. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  9647. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  9648. {
  9649. // Observe, that the below checks are only necessary for when unsafe references have been
  9650. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  9651. // for these value types.
  9652. // Don't allow a primitive to be converted to a reference of another primitive type
  9653. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  9654. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  9655. {
  9656. asASSERT( engine->ep.allowUnsafeReferences );
  9657. return -1;
  9658. }
  9659. // Don't allow an enum to be converted to a reference of another enum type
  9660. if( desc->parameterTypes[paramNum].IsEnumType() &&
  9661. desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
  9662. {
  9663. asASSERT( engine->ep.allowUnsafeReferences );
  9664. return -1;
  9665. }
  9666. // Don't allow a non-handle expression to be converted to a reference to a handle
  9667. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  9668. !argExpr->type.dataType.IsObjectHandle() )
  9669. {
  9670. asASSERT( engine->ep.allowUnsafeReferences );
  9671. return -1;
  9672. }
  9673. // Don't allow a value type to be converted
  9674. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  9675. (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
  9676. {
  9677. asASSERT( engine->ep.allowUnsafeReferences );
  9678. return -1;
  9679. }
  9680. }
  9681. // How well does the argument match the function parameter?
  9682. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  9683. return cost;
  9684. // No match is available
  9685. return -1;
  9686. }
  9687. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  9688. {
  9689. // Reference parameters whose value won't be used don't evaluate the expression
  9690. if( paramType->IsReference() && !(refType & asTM_INREF) )
  9691. {
  9692. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  9693. asSExprContext *orig = asNEW(asSExprContext)(engine);
  9694. if( orig == 0 )
  9695. {
  9696. // Out of memory
  9697. return;
  9698. }
  9699. MergeExprBytecodeAndType(orig, arg);
  9700. arg->origExpr = orig;
  9701. }
  9702. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  9703. // arg still holds the original expression for output parameters
  9704. ctx->bc.AddCode(&arg->bc);
  9705. }
  9706. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool isHandle)
  9707. {
  9708. DetermineSingleFunc(lctx, node);
  9709. DetermineSingleFunc(rctx, node);
  9710. ctx->exprNode = node;
  9711. // What type of operator is it?
  9712. int token = node->tokenType;
  9713. if( token == ttUnrecognizedToken )
  9714. {
  9715. // This happens when the compiler is inferring an assignment
  9716. // operation from another action, for example in preparing a value
  9717. // as a function argument
  9718. token = ttAssignment;
  9719. }
  9720. // boolean operators are not overloadable
  9721. if( token == ttAnd ||
  9722. token == ttOr ||
  9723. token == ttXor )
  9724. return false;
  9725. // Dual operators can also be implemented as class methods
  9726. if( token == ttEqual ||
  9727. token == ttNotEqual )
  9728. {
  9729. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9730. // Find the matching opEquals method
  9731. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9732. if( r == 0 )
  9733. {
  9734. // Try again by switching the order of the operands
  9735. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9736. }
  9737. if( r == 1 )
  9738. {
  9739. if( token == ttNotEqual )
  9740. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9741. // Success, don't continue
  9742. return true;
  9743. }
  9744. else if( r < 0 )
  9745. {
  9746. // Compiler error, don't continue
  9747. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9748. return true;
  9749. }
  9750. }
  9751. if( token == ttEqual ||
  9752. token == ttNotEqual ||
  9753. token == ttLessThan ||
  9754. token == ttLessThanOrEqual ||
  9755. token == ttGreaterThan ||
  9756. token == ttGreaterThanOrEqual )
  9757. {
  9758. bool swappedOrder = false;
  9759. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9760. // Find the matching opCmp method
  9761. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  9762. if( r == 0 )
  9763. {
  9764. // Try again by switching the order of the operands
  9765. swappedOrder = true;
  9766. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  9767. }
  9768. if( r == 1 )
  9769. {
  9770. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9771. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  9772. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  9773. if( token == ttEqual )
  9774. ctx->bc.Instr(asBC_TZ);
  9775. else if( token == ttNotEqual )
  9776. ctx->bc.Instr(asBC_TNZ);
  9777. else if( (token == ttLessThan && !swappedOrder) ||
  9778. (token == ttGreaterThan && swappedOrder) )
  9779. ctx->bc.Instr(asBC_TS);
  9780. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  9781. (token == ttGreaterThanOrEqual && swappedOrder) )
  9782. ctx->bc.Instr(asBC_TNP);
  9783. else if( (token == ttGreaterThan && !swappedOrder) ||
  9784. (token == ttLessThan && swappedOrder) )
  9785. ctx->bc.Instr(asBC_TP);
  9786. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  9787. (token == ttLessThanOrEqual && swappedOrder) )
  9788. ctx->bc.Instr(asBC_TNS);
  9789. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9790. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  9791. // Success, don't continue
  9792. return true;
  9793. }
  9794. else if( r < 0 )
  9795. {
  9796. // Compiler error, don't continue
  9797. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9798. return true;
  9799. }
  9800. }
  9801. // The rest of the operators are not commutative, and doesn't require specific return type
  9802. const char *op = 0, *op_r = 0;
  9803. switch( token )
  9804. {
  9805. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  9806. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  9807. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  9808. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  9809. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  9810. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  9811. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  9812. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  9813. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  9814. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  9815. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  9816. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  9817. }
  9818. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  9819. if( op && op_r )
  9820. {
  9821. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9822. // Find the matching operator method
  9823. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  9824. if( r == 0 )
  9825. {
  9826. // Try again by switching the order of the operands, and using the reversed operator
  9827. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  9828. }
  9829. if( r == 1 )
  9830. {
  9831. // Success, don't continue
  9832. return true;
  9833. }
  9834. else if( r < 0 )
  9835. {
  9836. // Compiler error, don't continue
  9837. ctx->type.SetDummy();
  9838. return true;
  9839. }
  9840. }
  9841. // Assignment operators
  9842. op = 0;
  9843. if( isHandle )
  9844. {
  9845. // Only asOBJ_ASHANDLE types can get here
  9846. asASSERT( lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) );
  9847. asASSERT( token == ttAssignment );
  9848. if( token == ttAssignment )
  9849. op = "opHndlAssign";
  9850. }
  9851. else
  9852. {
  9853. switch( token )
  9854. {
  9855. case ttAssignment: op = "opAssign"; break;
  9856. case ttAddAssign: op = "opAddAssign"; break;
  9857. case ttSubAssign: op = "opSubAssign"; break;
  9858. case ttMulAssign: op = "opMulAssign"; break;
  9859. case ttDivAssign: op = "opDivAssign"; break;
  9860. case ttModAssign: op = "opModAssign"; break;
  9861. case ttPowAssign: op = "opPowAssign"; break;
  9862. case ttOrAssign: op = "opOrAssign"; break;
  9863. case ttAndAssign: op = "opAndAssign"; break;
  9864. case ttXorAssign: op = "opXorAssign"; break;
  9865. case ttShiftLeftAssign: op = "opShlAssign"; break;
  9866. case ttShiftRightLAssign: op = "opShrAssign"; break;
  9867. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  9868. }
  9869. }
  9870. if( op )
  9871. {
  9872. if( builder->engine->ep.disallowValueAssignForRefType &&
  9873. lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  9874. {
  9875. if( token == ttAssignment )
  9876. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  9877. else
  9878. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  9879. // Set a dummy output
  9880. ctx->type.Set(lctx->type.dataType);
  9881. return true;
  9882. }
  9883. // TODO: Shouldn't accept const lvalue with the assignment operators
  9884. // Find the matching operator method
  9885. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  9886. if( r == 1 )
  9887. {
  9888. // Success, don't continue
  9889. return true;
  9890. }
  9891. else if( r < 0 )
  9892. {
  9893. // Compiler error, don't continue
  9894. ctx->type.SetDummy();
  9895. return true;
  9896. }
  9897. }
  9898. // No suitable operator was found
  9899. return false;
  9900. }
  9901. // Returns negative on compile error
  9902. // zero on no matching operator
  9903. // one on matching operator
  9904. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  9905. {
  9906. // Find the matching method
  9907. if( lctx->type.dataType.IsObject() &&
  9908. (!lctx->type.isExplicitHandle ||
  9909. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  9910. {
  9911. asUINT n;
  9912. // Is the left value a const?
  9913. bool isConst = lctx->type.dataType.IsObjectConst();
  9914. asCArray<int> funcs;
  9915. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  9916. for( n = 0; n < ot->methods.GetLength(); n++ )
  9917. {
  9918. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9919. asASSERT( func );
  9920. if( func && func->name == methodName &&
  9921. (!specificReturn || func->returnType == returnType) &&
  9922. func->parameterTypes.GetLength() == 1 &&
  9923. (!isConst || func->isReadOnly) )
  9924. {
  9925. // Make sure the method is accessible by the module
  9926. if( builder->module->accessMask & func->accessMask )
  9927. {
  9928. funcs.PushLast(func->id);
  9929. }
  9930. }
  9931. }
  9932. // Which is the best matching function?
  9933. asCArray<asSOverloadCandidate> tempFuncs;
  9934. MatchArgument(funcs, tempFuncs, rctx, 0);
  9935. // Find the lowest cost operator(s)
  9936. asCArray<int> ops;
  9937. asUINT bestCost = asUINT(-1);
  9938. for( n = 0; n < tempFuncs.GetLength(); ++n )
  9939. {
  9940. asUINT cost = tempFuncs[n].cost;
  9941. if( cost < bestCost )
  9942. {
  9943. ops.SetLength(0);
  9944. bestCost = cost;
  9945. }
  9946. if( cost == bestCost )
  9947. ops.PushLast(tempFuncs[n].funcId);
  9948. }
  9949. // If the object is not const, then we need to prioritize non-const methods
  9950. if( !isConst )
  9951. FilterConst(ops);
  9952. // Did we find an operator?
  9953. if( ops.GetLength() == 1 )
  9954. {
  9955. // Process the lctx expression as get accessor
  9956. ProcessPropertyGetAccessor(lctx, node);
  9957. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  9958. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  9959. asCArray<int> usedVars;
  9960. lctx->bc.GetVarsUsed(usedVars);
  9961. size_t oldReservedVars = reservedVariables.GetLength();
  9962. for( asUINT n = 0; n < rctx->deferredParams.GetLength(); n++ )
  9963. {
  9964. if( usedVars.Exists(rctx->deferredParams[n].argType.stackOffset) )
  9965. {
  9966. if( reservedVariables.GetLength() == oldReservedVars )
  9967. reservedVariables.Concatenate(usedVars);
  9968. // Allocate a new variable for the deferred argument
  9969. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  9970. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  9971. rctx->deferredParams[n].argType.stackOffset = short(offset);
  9972. rctx->bc.ExchangeVar(oldVar, offset);
  9973. ReleaseTemporaryVariable(oldVar, 0);
  9974. }
  9975. }
  9976. reservedVariables.SetLength(oldReservedVars);
  9977. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  9978. asCArray<asSExprContext *> args;
  9979. args.PushLast(rctx);
  9980. MergeExprBytecode(ctx, lctx);
  9981. ctx->type = lctx->type;
  9982. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  9983. // Found matching operator
  9984. return 1;
  9985. }
  9986. else if( ops.GetLength() > 1 )
  9987. {
  9988. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9989. PrintMatchingFuncs(ops, node);
  9990. ctx->type.SetDummy();
  9991. // Compiler error
  9992. return -1;
  9993. }
  9994. }
  9995. // No matching operator
  9996. return 0;
  9997. }
  9998. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  9999. {
  10000. if( objectType )
  10001. {
  10002. Dereference(ctx, true);
  10003. // This following warning was removed as there may be valid reasons
  10004. // for calling non-const methods on temporary objects, and we shouldn't
  10005. // warn when there is no way of removing the warning.
  10006. /*
  10007. // Warn if the method is non-const and the object is temporary
  10008. // since the changes will be lost when the object is destroyed.
  10009. // If the object is accessed through a handle, then it is assumed
  10010. // the object is not temporary, even though the handle is.
  10011. if( ctx->type.isTemporary &&
  10012. !ctx->type.dataType.IsObjectHandle() &&
  10013. !engine->scriptFunctions[funcId]->isReadOnly )
  10014. {
  10015. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  10016. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  10017. }
  10018. */ }
  10019. asCByteCode objBC(engine);
  10020. objBC.AddCode(&ctx->bc);
  10021. PrepareFunctionCall(funcId, &ctx->bc, args);
  10022. // Verify if any of the args variable offsets are used in the other code.
  10023. // If they are exchange the offset for a new one
  10024. asUINT n;
  10025. for( n = 0; n < args.GetLength(); n++ )
  10026. {
  10027. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  10028. {
  10029. // Release the current temporary variable
  10030. ReleaseTemporaryVariable(args[n]->type, 0);
  10031. asCDataType dt = args[n]->type.dataType;
  10032. dt.MakeReference(false);
  10033. int l = int(reservedVariables.GetLength());
  10034. objBC.GetVarsUsed(reservedVariables);
  10035. ctx->bc.GetVarsUsed(reservedVariables);
  10036. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  10037. reservedVariables.SetLength(l);
  10038. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  10039. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  10040. args[n]->type.stackOffset = (short)newOffset;
  10041. args[n]->type.isTemporary = true;
  10042. args[n]->type.isVariable = true;
  10043. }
  10044. }
  10045. // If the function will return a value type on the stack, then we must allocate space
  10046. // for that here and push the address on the stack as a hidden argument to the function
  10047. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  10048. if( func->DoesReturnOnStack() )
  10049. {
  10050. asASSERT(!useVariable);
  10051. useVariable = true;
  10052. stackOffset = AllocateVariable(func->returnType, true);
  10053. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  10054. }
  10055. ctx->bc.AddCode(&objBC);
  10056. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  10057. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  10058. }
  10059. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10060. {
  10061. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  10062. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  10063. {
  10064. Error(TXT_INVALID_OP_ON_METHOD, node);
  10065. return -1;
  10066. }
  10067. // Don't allow any operators on void expressions
  10068. if( lctx->type.IsVoidExpression() || rctx->type.IsVoidExpression() )
  10069. {
  10070. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10071. return -1;
  10072. }
  10073. IsVariableInitialized(&lctx->type, node);
  10074. IsVariableInitialized(&rctx->type, node);
  10075. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  10076. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  10077. node->tokenType == ttIs || node->tokenType == ttNotIs )
  10078. {
  10079. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  10080. return 0;
  10081. }
  10082. else
  10083. {
  10084. // Compile an overloaded operator for the two operands
  10085. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  10086. return 0;
  10087. // If both operands are objects, then we shouldn't continue
  10088. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  10089. {
  10090. asCString str;
  10091. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  10092. Error(str, node);
  10093. ctx->type.SetDummy();
  10094. return -1;
  10095. }
  10096. // Process the property get accessors (if any)
  10097. ProcessPropertyGetAccessor(lctx, node);
  10098. ProcessPropertyGetAccessor(rctx, node);
  10099. // Make sure we have two variables or constants
  10100. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  10101. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  10102. // Make sure lctx doesn't end up with a variable used in rctx
  10103. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10104. {
  10105. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  10106. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  10107. ReleaseTemporaryVariable(offset, 0);
  10108. }
  10109. // Math operators
  10110. // + - * / % ** += -= *= /= %= **=
  10111. int op = node->tokenType;
  10112. if( op == ttPlus || op == ttAddAssign ||
  10113. op == ttMinus || op == ttSubAssign ||
  10114. op == ttStar || op == ttMulAssign ||
  10115. op == ttSlash || op == ttDivAssign ||
  10116. op == ttPercent || op == ttModAssign ||
  10117. op == ttStarStar || op == ttPowAssign )
  10118. {
  10119. CompileMathOperator(node, lctx, rctx, ctx);
  10120. return 0;
  10121. }
  10122. // Bitwise operators
  10123. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  10124. if( op == ttAmp || op == ttAndAssign ||
  10125. op == ttBitOr || op == ttOrAssign ||
  10126. op == ttBitXor || op == ttXorAssign ||
  10127. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  10128. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  10129. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10130. {
  10131. CompileBitwiseOperator(node, lctx, rctx, ctx);
  10132. return 0;
  10133. }
  10134. // Comparison operators
  10135. // == != < > <= >=
  10136. if( op == ttEqual || op == ttNotEqual ||
  10137. op == ttLessThan || op == ttLessThanOrEqual ||
  10138. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  10139. {
  10140. CompileComparisonOperator(node, lctx, rctx, ctx);
  10141. return 0;
  10142. }
  10143. // Boolean operators
  10144. // && || ^^
  10145. if( op == ttAnd || op == ttOr || op == ttXor )
  10146. {
  10147. CompileBooleanOperator(node, lctx, rctx, ctx);
  10148. return 0;
  10149. }
  10150. }
  10151. asASSERT(false);
  10152. return -1;
  10153. }
  10154. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  10155. {
  10156. int l = int(reservedVariables.GetLength());
  10157. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  10158. ConvertToTempVariable(ctx);
  10159. reservedVariables.SetLength(l);
  10160. }
  10161. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  10162. {
  10163. // This is only used for primitive types and null handles
  10164. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  10165. ConvertToVariable(ctx);
  10166. if( !ctx->type.isTemporary )
  10167. {
  10168. if( ctx->type.dataType.IsPrimitive() )
  10169. {
  10170. // Copy the variable to a temporary variable
  10171. int offset = AllocateVariable(ctx->type.dataType, true);
  10172. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10173. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  10174. else
  10175. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  10176. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10177. }
  10178. else
  10179. {
  10180. // We should never get here
  10181. asASSERT(false);
  10182. }
  10183. }
  10184. }
  10185. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  10186. {
  10187. // We should never get here while the context is still an unprocessed property accessor
  10188. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  10189. int offset;
  10190. if( !ctx->type.isVariable &&
  10191. (ctx->type.dataType.IsObjectHandle() ||
  10192. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  10193. {
  10194. offset = AllocateVariable(ctx->type.dataType, true);
  10195. if( ctx->type.IsNullConstant() )
  10196. {
  10197. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  10198. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  10199. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  10200. }
  10201. else
  10202. {
  10203. Dereference(ctx, true);
  10204. // Copy the object handle to a variable
  10205. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10206. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  10207. ctx->bc.Instr(asBC_PopPtr);
  10208. }
  10209. // As this is an object the reference must be placed on the stack
  10210. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10211. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10212. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10213. ctx->type.dataType.MakeHandle(true);
  10214. ctx->type.dataType.MakeReference(true);
  10215. }
  10216. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  10217. ctx->type.dataType.IsPrimitive() )
  10218. {
  10219. if( ctx->type.isConstant )
  10220. {
  10221. offset = AllocateVariable(ctx->type.dataType, true);
  10222. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10223. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  10224. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10225. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  10226. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10227. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  10228. else
  10229. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  10230. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10231. return;
  10232. }
  10233. else
  10234. {
  10235. asASSERT(ctx->type.dataType.IsPrimitive());
  10236. asASSERT(ctx->type.dataType.IsReference());
  10237. ctx->type.dataType.MakeReference(false);
  10238. offset = AllocateVariable(ctx->type.dataType, true);
  10239. // Read the value from the address in the register directly into the variable
  10240. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10241. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  10242. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10243. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  10244. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10245. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  10246. else
  10247. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  10248. }
  10249. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10250. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  10251. }
  10252. }
  10253. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  10254. {
  10255. int l = int(reservedVariables.GetLength());
  10256. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  10257. ConvertToVariable(ctx);
  10258. reservedVariables.SetLength(l);
  10259. }
  10260. void asCCompiler::ImplicitConvObjectToBestMathType(asSExprContext *ctx, asCScriptNode *node)
  10261. {
  10262. asCArray<int> funcs;
  10263. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  10264. if( beh )
  10265. {
  10266. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  10267. {
  10268. // Consider only implicit casts
  10269. // TODO: 2.29.0: Look for opImplConv methods instead
  10270. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  10271. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  10272. funcs.PushLast(beh->operators[n+1]);
  10273. }
  10274. // Use the one with the highest precision
  10275. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  10276. while( funcs.GetLength() > 1 )
  10277. {
  10278. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  10279. int value1 = 11, value2 = 11;
  10280. for( asUINT i = 0; i < 10; i++ )
  10281. {
  10282. if( returnType == match[i] )
  10283. {
  10284. value1 = i;
  10285. break;
  10286. }
  10287. }
  10288. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  10289. {
  10290. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  10291. for( asUINT i = 0; i < 10; i++ )
  10292. {
  10293. if( returnType == match[i] )
  10294. {
  10295. value2 = i;
  10296. break;
  10297. }
  10298. }
  10299. if( value2 >= value1 )
  10300. {
  10301. // Remove this and continue searching
  10302. funcs.RemoveIndexUnordered(n--);
  10303. }
  10304. else
  10305. {
  10306. // Remove the first, and start over
  10307. funcs.RemoveIndexUnordered(0);
  10308. break;
  10309. }
  10310. }
  10311. }
  10312. // Do the conversion
  10313. if( funcs.GetLength() )
  10314. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  10315. }
  10316. }
  10317. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10318. {
  10319. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  10320. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  10321. // If either operand is a non-primitive then use the primitive type
  10322. if( !lctx->type.dataType.IsPrimitive() )
  10323. ImplicitConvObjectToBestMathType(lctx, node);
  10324. if( !rctx->type.dataType.IsPrimitive() )
  10325. ImplicitConvObjectToBestMathType(rctx, node);
  10326. // Both types must now be primitives. Implicitly convert them so they match
  10327. asCDataType to;
  10328. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  10329. to.SetTokenType(ttDouble);
  10330. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  10331. to.SetTokenType(ttFloat);
  10332. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10333. {
  10334. // Convert to int64 if both are signed or if one is non-constant and signed
  10335. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10336. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10337. to.SetTokenType(ttInt64);
  10338. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10339. to.SetTokenType(ttUInt64);
  10340. else
  10341. to.SetTokenType(ttInt64);
  10342. }
  10343. else
  10344. {
  10345. // Convert to int32 if both are signed or if one is non-constant and signed
  10346. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10347. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10348. to.SetTokenType(ttInt);
  10349. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10350. to.SetTokenType(ttUInt);
  10351. else
  10352. to.SetTokenType(ttInt);
  10353. }
  10354. // If doing an operation with double constant and float variable, the constant should be converted to float
  10355. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  10356. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  10357. to.SetTokenType(ttFloat);
  10358. // Do the actual conversion
  10359. int l = int(reservedVariables.GetLength());
  10360. rctx->bc.GetVarsUsed(reservedVariables);
  10361. lctx->bc.GetVarsUsed(reservedVariables);
  10362. if( lctx->type.dataType.IsReference() )
  10363. ConvertToVariable(lctx);
  10364. if( rctx->type.dataType.IsReference() )
  10365. ConvertToVariable(rctx);
  10366. int op = node->tokenType;
  10367. if( to.IsPrimitive() )
  10368. {
  10369. // ttStarStar allows an integer, right-hand operand and a double
  10370. // left-hand operand.
  10371. if( (op == ttStarStar || op == ttPowAssign) &&
  10372. lctx->type.dataType.IsDoubleType() &&
  10373. (rctx->type.dataType.IsIntegerType() ||
  10374. rctx->type.dataType.IsUnsignedType()) )
  10375. {
  10376. to.SetTokenType(ttInt);
  10377. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  10378. to.SetTokenType(ttDouble);
  10379. }
  10380. else
  10381. {
  10382. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  10383. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  10384. }
  10385. }
  10386. reservedVariables.SetLength(l);
  10387. // Verify that the conversion was successful
  10388. if( !lctx->type.dataType.IsIntegerType() &&
  10389. !lctx->type.dataType.IsUnsignedType() &&
  10390. !lctx->type.dataType.IsFloatType() &&
  10391. !lctx->type.dataType.IsDoubleType() )
  10392. {
  10393. asCString str;
  10394. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  10395. Error(str, node);
  10396. ctx->type.SetDummy();
  10397. return;
  10398. }
  10399. if( !rctx->type.dataType.IsIntegerType() &&
  10400. !rctx->type.dataType.IsUnsignedType() &&
  10401. !rctx->type.dataType.IsFloatType() &&
  10402. !rctx->type.dataType.IsDoubleType() )
  10403. {
  10404. asCString str;
  10405. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  10406. Error(str, node);
  10407. ctx->type.SetDummy();
  10408. return;
  10409. }
  10410. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10411. // Verify if we are dividing with a constant zero
  10412. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  10413. (op == ttSlash || op == ttDivAssign ||
  10414. op == ttPercent || op == ttModAssign) )
  10415. {
  10416. Error(TXT_DIVIDE_BY_ZERO, node);
  10417. }
  10418. if( !isConstant )
  10419. {
  10420. ConvertToVariableNotIn(lctx, rctx);
  10421. ConvertToVariableNotIn(rctx, lctx);
  10422. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10423. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10424. if( op == ttAddAssign || op == ttSubAssign ||
  10425. op == ttMulAssign || op == ttDivAssign ||
  10426. op == ttModAssign || op == ttPowAssign )
  10427. {
  10428. // Merge the operands in the different order so that they are evaluated correctly
  10429. MergeExprBytecode(ctx, rctx);
  10430. MergeExprBytecode(ctx, lctx);
  10431. // We must not process the deferred parameters yet, as
  10432. // it may overwrite the lvalue kept in the register
  10433. }
  10434. else
  10435. {
  10436. MergeExprBytecode(ctx, lctx);
  10437. MergeExprBytecode(ctx, rctx);
  10438. ProcessDeferredParams(ctx);
  10439. }
  10440. asEBCInstr instruction = asBC_ADDi;
  10441. if( lctx->type.dataType.IsIntegerType() ||
  10442. lctx->type.dataType.IsUnsignedType() )
  10443. {
  10444. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10445. {
  10446. if( op == ttPlus || op == ttAddAssign )
  10447. instruction = asBC_ADDi;
  10448. else if( op == ttMinus || op == ttSubAssign )
  10449. instruction = asBC_SUBi;
  10450. else if( op == ttStar || op == ttMulAssign )
  10451. instruction = asBC_MULi;
  10452. else if( op == ttSlash || op == ttDivAssign )
  10453. {
  10454. if( lctx->type.dataType.IsIntegerType() )
  10455. instruction = asBC_DIVi;
  10456. else
  10457. instruction = asBC_DIVu;
  10458. }
  10459. else if( op == ttPercent || op == ttModAssign )
  10460. {
  10461. if( lctx->type.dataType.IsIntegerType() )
  10462. instruction = asBC_MODi;
  10463. else
  10464. instruction = asBC_MODu;
  10465. }
  10466. else if( op == ttStarStar || op == ttPowAssign )
  10467. {
  10468. if( lctx->type.dataType.IsIntegerType() )
  10469. instruction = asBC_POWi;
  10470. else
  10471. instruction = asBC_POWu;
  10472. }
  10473. }
  10474. else
  10475. {
  10476. if( op == ttPlus || op == ttAddAssign )
  10477. instruction = asBC_ADDi64;
  10478. else if( op == ttMinus || op == ttSubAssign )
  10479. instruction = asBC_SUBi64;
  10480. else if( op == ttStar || op == ttMulAssign )
  10481. instruction = asBC_MULi64;
  10482. else if( op == ttSlash || op == ttDivAssign )
  10483. {
  10484. if( lctx->type.dataType.IsIntegerType() )
  10485. instruction = asBC_DIVi64;
  10486. else
  10487. instruction = asBC_DIVu64;
  10488. }
  10489. else if( op == ttPercent || op == ttModAssign )
  10490. {
  10491. if( lctx->type.dataType.IsIntegerType() )
  10492. instruction = asBC_MODi64;
  10493. else
  10494. instruction = asBC_MODu64;
  10495. }
  10496. else if( op == ttStarStar || op == ttPowAssign )
  10497. {
  10498. if( lctx->type.dataType.IsIntegerType() )
  10499. instruction = asBC_POWi64;
  10500. else
  10501. instruction = asBC_POWu64;
  10502. }
  10503. }
  10504. }
  10505. else if( lctx->type.dataType.IsFloatType() )
  10506. {
  10507. if( op == ttPlus || op == ttAddAssign )
  10508. instruction = asBC_ADDf;
  10509. else if( op == ttMinus || op == ttSubAssign )
  10510. instruction = asBC_SUBf;
  10511. else if( op == ttStar || op == ttMulAssign )
  10512. instruction = asBC_MULf;
  10513. else if( op == ttSlash || op == ttDivAssign )
  10514. instruction = asBC_DIVf;
  10515. else if( op == ttPercent || op == ttModAssign )
  10516. instruction = asBC_MODf;
  10517. else if( op == ttStarStar || op == ttPowAssign )
  10518. instruction = asBC_POWf;
  10519. }
  10520. else if( lctx->type.dataType.IsDoubleType() )
  10521. {
  10522. if( rctx->type.dataType.IsIntegerType() )
  10523. {
  10524. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  10525. if( op == ttStarStar || op == ttPowAssign )
  10526. instruction = asBC_POWdi;
  10527. else
  10528. asASSERT(false); // Should not be possible
  10529. }
  10530. else
  10531. {
  10532. if( op == ttPlus || op == ttAddAssign )
  10533. instruction = asBC_ADDd;
  10534. else if( op == ttMinus || op == ttSubAssign )
  10535. instruction = asBC_SUBd;
  10536. else if( op == ttStar || op == ttMulAssign )
  10537. instruction = asBC_MULd;
  10538. else if( op == ttSlash || op == ttDivAssign )
  10539. instruction = asBC_DIVd;
  10540. else if( op == ttPercent || op == ttModAssign )
  10541. instruction = asBC_MODd;
  10542. else if( op == ttStarStar || op == ttPowAssign )
  10543. instruction = asBC_POWd;
  10544. }
  10545. }
  10546. else
  10547. {
  10548. // Shouldn't be possible
  10549. asASSERT(false);
  10550. }
  10551. // Do the operation
  10552. int a = AllocateVariable(lctx->type.dataType, true);
  10553. int b = lctx->type.stackOffset;
  10554. int c = rctx->type.stackOffset;
  10555. ctx->bc.InstrW_W_W(instruction, a, b, c);
  10556. ctx->type.SetVariable(lctx->type.dataType, a, true);
  10557. }
  10558. else
  10559. {
  10560. // Both values are constants
  10561. if( lctx->type.dataType.IsIntegerType() ||
  10562. lctx->type.dataType.IsUnsignedType() )
  10563. {
  10564. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10565. {
  10566. int v = 0;
  10567. if( op == ttPlus )
  10568. v = lctx->type.intValue + rctx->type.intValue;
  10569. else if( op == ttMinus )
  10570. v = lctx->type.intValue - rctx->type.intValue;
  10571. else if( op == ttStar )
  10572. v = lctx->type.intValue * rctx->type.intValue;
  10573. else if( op == ttSlash )
  10574. {
  10575. // TODO: Should probably report an error, rather than silently convert the value to 0
  10576. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  10577. v = 0;
  10578. else
  10579. if( lctx->type.dataType.IsIntegerType() )
  10580. v = lctx->type.intValue / rctx->type.intValue;
  10581. else
  10582. v = lctx->type.dwordValue / rctx->type.dwordValue;
  10583. }
  10584. else if( op == ttPercent )
  10585. {
  10586. // TODO: Should probably report an error, rather than silently convert the value to 0
  10587. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  10588. v = 0;
  10589. else
  10590. if( lctx->type.dataType.IsIntegerType() )
  10591. v = lctx->type.intValue % rctx->type.intValue;
  10592. else
  10593. v = lctx->type.dwordValue % rctx->type.dwordValue;
  10594. }
  10595. else if( op == ttStarStar )
  10596. {
  10597. bool isOverflow;
  10598. if( lctx->type.dataType.IsIntegerType() )
  10599. v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow);
  10600. else
  10601. v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow);
  10602. }
  10603. ctx->type.SetConstantDW(lctx->type.dataType, v);
  10604. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  10605. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  10606. ctx->type.dataType.SetTokenType(ttInt);
  10607. }
  10608. else
  10609. {
  10610. asQWORD v = 0;
  10611. if( op == ttPlus )
  10612. v = lctx->type.qwordValue + rctx->type.qwordValue;
  10613. else if( op == ttMinus )
  10614. v = lctx->type.qwordValue - rctx->type.qwordValue;
  10615. else if( op == ttStar )
  10616. v = lctx->type.qwordValue * rctx->type.qwordValue;
  10617. else if( op == ttSlash )
  10618. {
  10619. // TODO: Should probably report an error, rather than silently convert the value to 0
  10620. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  10621. v = 0;
  10622. else
  10623. if( lctx->type.dataType.IsIntegerType() )
  10624. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  10625. else
  10626. v = lctx->type.qwordValue / rctx->type.qwordValue;
  10627. }
  10628. else if( op == ttPercent )
  10629. {
  10630. // TODO: Should probably report an error, rather than silently convert the value to 0
  10631. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  10632. v = 0;
  10633. else
  10634. if( lctx->type.dataType.IsIntegerType() )
  10635. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  10636. else
  10637. v = lctx->type.qwordValue % rctx->type.qwordValue;
  10638. }
  10639. else if( op == ttStarStar )
  10640. {
  10641. bool isOverflow;
  10642. if( lctx->type.dataType.IsIntegerType() )
  10643. v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow);
  10644. else
  10645. v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow);
  10646. }
  10647. ctx->type.SetConstantQW(lctx->type.dataType, v);
  10648. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  10649. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  10650. ctx->type.dataType.SetTokenType(ttInt64);
  10651. }
  10652. }
  10653. else if( lctx->type.dataType.IsFloatType() )
  10654. {
  10655. float v = 0.0f;
  10656. if( op == ttPlus )
  10657. v = lctx->type.floatValue + rctx->type.floatValue;
  10658. else if( op == ttMinus )
  10659. v = lctx->type.floatValue - rctx->type.floatValue;
  10660. else if( op == ttStar )
  10661. v = lctx->type.floatValue * rctx->type.floatValue;
  10662. else if( op == ttSlash )
  10663. {
  10664. if( rctx->type.floatValue == 0 )
  10665. v = 0;
  10666. else
  10667. v = lctx->type.floatValue / rctx->type.floatValue;
  10668. }
  10669. else if( op == ttPercent )
  10670. {
  10671. if( rctx->type.floatValue == 0 )
  10672. v = 0;
  10673. else
  10674. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  10675. }
  10676. else if( op == ttStarStar )
  10677. v = pow(lctx->type.floatValue, rctx->type.floatValue);
  10678. ctx->type.SetConstantF(lctx->type.dataType, v);
  10679. }
  10680. else if( lctx->type.dataType.IsDoubleType() )
  10681. {
  10682. double v = 0.0;
  10683. if( rctx->type.dataType.IsIntegerType() )
  10684. {
  10685. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  10686. if( op == ttStarStar || op == ttPowAssign )
  10687. v = pow(lctx->type.doubleValue, rctx->type.intValue);
  10688. else
  10689. asASSERT(false); // Should not be possible
  10690. }
  10691. else
  10692. {
  10693. if( op == ttPlus )
  10694. v = lctx->type.doubleValue + rctx->type.doubleValue;
  10695. else if( op == ttMinus )
  10696. v = lctx->type.doubleValue - rctx->type.doubleValue;
  10697. else if( op == ttStar )
  10698. v = lctx->type.doubleValue * rctx->type.doubleValue;
  10699. else if( op == ttSlash )
  10700. {
  10701. if( rctx->type.doubleValue == 0 )
  10702. v = 0;
  10703. else
  10704. v = lctx->type.doubleValue / rctx->type.doubleValue;
  10705. }
  10706. else if( op == ttPercent )
  10707. {
  10708. if( rctx->type.doubleValue == 0 )
  10709. v = 0;
  10710. else
  10711. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  10712. }
  10713. else if( op == ttStarStar )
  10714. v = pow(lctx->type.doubleValue, rctx->type.doubleValue);
  10715. }
  10716. ctx->type.SetConstantD(lctx->type.dataType, v);
  10717. }
  10718. else
  10719. {
  10720. // Shouldn't be possible
  10721. asASSERT(false);
  10722. }
  10723. }
  10724. }
  10725. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10726. {
  10727. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  10728. eTokenType op = node->tokenType;
  10729. if( op == ttAmp || op == ttAndAssign ||
  10730. op == ttBitOr || op == ttOrAssign ||
  10731. op == ttBitXor || op == ttXorAssign )
  10732. {
  10733. // Convert left hand operand to integer if it's not already one
  10734. asCDataType to;
  10735. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  10736. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10737. to.SetTokenType(ttInt64);
  10738. else
  10739. to.SetTokenType(ttInt);
  10740. // Do the actual conversion (keep sign/unsigned if possible)
  10741. int l = int(reservedVariables.GetLength());
  10742. rctx->bc.GetVarsUsed(reservedVariables);
  10743. if( lctx->type.dataType.IsUnsignedType() )
  10744. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  10745. else
  10746. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  10747. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  10748. reservedVariables.SetLength(l);
  10749. // Verify that the conversion was successful
  10750. if( lctx->type.dataType != to )
  10751. {
  10752. asCString str;
  10753. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10754. Error(str, node);
  10755. }
  10756. // Convert right hand operand to same size as left hand
  10757. l = int(reservedVariables.GetLength());
  10758. lctx->bc.GetVarsUsed(reservedVariables);
  10759. if( rctx->type.dataType.IsUnsignedType() )
  10760. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  10761. else
  10762. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  10763. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  10764. reservedVariables.SetLength(l);
  10765. if( rctx->type.dataType != to )
  10766. {
  10767. asCString str;
  10768. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  10769. Error(str, node);
  10770. }
  10771. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10772. if( !isConstant )
  10773. {
  10774. ConvertToVariableNotIn(lctx, rctx);
  10775. ConvertToVariableNotIn(rctx, lctx);
  10776. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10777. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10778. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  10779. {
  10780. // Compound assignments execute the right hand value first
  10781. MergeExprBytecode(ctx, rctx);
  10782. MergeExprBytecode(ctx, lctx);
  10783. }
  10784. else
  10785. {
  10786. MergeExprBytecode(ctx, lctx);
  10787. MergeExprBytecode(ctx, rctx);
  10788. }
  10789. ProcessDeferredParams(ctx);
  10790. asEBCInstr instruction = asBC_BAND;
  10791. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10792. {
  10793. if( op == ttAmp || op == ttAndAssign )
  10794. instruction = asBC_BAND;
  10795. else if( op == ttBitOr || op == ttOrAssign )
  10796. instruction = asBC_BOR;
  10797. else if( op == ttBitXor || op == ttXorAssign )
  10798. instruction = asBC_BXOR;
  10799. }
  10800. else
  10801. {
  10802. if( op == ttAmp || op == ttAndAssign )
  10803. instruction = asBC_BAND64;
  10804. else if( op == ttBitOr || op == ttOrAssign )
  10805. instruction = asBC_BOR64;
  10806. else if( op == ttBitXor || op == ttXorAssign )
  10807. instruction = asBC_BXOR64;
  10808. }
  10809. // Do the operation
  10810. int a = AllocateVariable(lctx->type.dataType, true);
  10811. int b = lctx->type.stackOffset;
  10812. int c = rctx->type.stackOffset;
  10813. ctx->bc.InstrW_W_W(instruction, a, b, c);
  10814. ctx->type.SetVariable(lctx->type.dataType, a, true);
  10815. }
  10816. else
  10817. {
  10818. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10819. {
  10820. asQWORD v = 0;
  10821. if( op == ttAmp )
  10822. v = lctx->type.qwordValue & rctx->type.qwordValue;
  10823. else if( op == ttBitOr )
  10824. v = lctx->type.qwordValue | rctx->type.qwordValue;
  10825. else if( op == ttBitXor )
  10826. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  10827. // Remember the result
  10828. ctx->type.SetConstantQW(lctx->type.dataType, v);
  10829. }
  10830. else
  10831. {
  10832. asDWORD v = 0;
  10833. if( op == ttAmp )
  10834. v = lctx->type.dwordValue & rctx->type.dwordValue;
  10835. else if( op == ttBitOr )
  10836. v = lctx->type.dwordValue | rctx->type.dwordValue;
  10837. else if( op == ttBitXor )
  10838. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  10839. // Remember the result
  10840. ctx->type.SetConstantDW(lctx->type.dataType, v);
  10841. }
  10842. }
  10843. }
  10844. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  10845. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  10846. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10847. {
  10848. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  10849. if( lctx->type.dataType.IsObject() )
  10850. {
  10851. asCString str;
  10852. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  10853. Error(str, node);
  10854. // Set an integer value and allow the compiler to continue
  10855. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  10856. return;
  10857. }
  10858. // Convert left hand operand to integer if it's not already one
  10859. asCDataType to = lctx->type.dataType;
  10860. if( lctx->type.dataType.IsUnsignedType() &&
  10861. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  10862. {
  10863. to = asCDataType::CreatePrimitive(ttUInt, false);
  10864. }
  10865. else if( !lctx->type.dataType.IsUnsignedType() )
  10866. {
  10867. asCDataType to;
  10868. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10869. to.SetTokenType(ttInt64);
  10870. else
  10871. to.SetTokenType(ttInt);
  10872. }
  10873. // Do the actual conversion
  10874. int l = int(reservedVariables.GetLength());
  10875. rctx->bc.GetVarsUsed(reservedVariables);
  10876. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  10877. reservedVariables.SetLength(l);
  10878. // Verify that the conversion was successful
  10879. if( lctx->type.dataType != to )
  10880. {
  10881. asCString str;
  10882. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10883. Error(str, node);
  10884. }
  10885. // Right operand must be 32bit uint
  10886. l = int(reservedVariables.GetLength());
  10887. lctx->bc.GetVarsUsed(reservedVariables);
  10888. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  10889. reservedVariables.SetLength(l);
  10890. if( !rctx->type.dataType.IsUnsignedType() )
  10891. {
  10892. asCString str;
  10893. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  10894. Error(str, node);
  10895. }
  10896. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10897. if( !isConstant )
  10898. {
  10899. ConvertToVariableNotIn(lctx, rctx);
  10900. ConvertToVariableNotIn(rctx, lctx);
  10901. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10902. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10903. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  10904. {
  10905. // Compound assignments execute the right hand value first
  10906. MergeExprBytecode(ctx, rctx);
  10907. MergeExprBytecode(ctx, lctx);
  10908. }
  10909. else
  10910. {
  10911. MergeExprBytecode(ctx, lctx);
  10912. MergeExprBytecode(ctx, rctx);
  10913. }
  10914. ProcessDeferredParams(ctx);
  10915. asEBCInstr instruction = asBC_BSLL;
  10916. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10917. {
  10918. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  10919. instruction = asBC_BSLL;
  10920. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  10921. instruction = asBC_BSRL;
  10922. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10923. instruction = asBC_BSRA;
  10924. }
  10925. else
  10926. {
  10927. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  10928. instruction = asBC_BSLL64;
  10929. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  10930. instruction = asBC_BSRL64;
  10931. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10932. instruction = asBC_BSRA64;
  10933. }
  10934. // Do the operation
  10935. int a = AllocateVariable(lctx->type.dataType, true);
  10936. int b = lctx->type.stackOffset;
  10937. int c = rctx->type.stackOffset;
  10938. ctx->bc.InstrW_W_W(instruction, a, b, c);
  10939. ctx->type.SetVariable(lctx->type.dataType, a, true);
  10940. }
  10941. else
  10942. {
  10943. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10944. {
  10945. asDWORD v = 0;
  10946. if( op == ttBitShiftLeft )
  10947. v = lctx->type.dwordValue << rctx->type.dwordValue;
  10948. else if( op == ttBitShiftRight )
  10949. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  10950. else if( op == ttBitShiftRightArith )
  10951. v = lctx->type.intValue >> rctx->type.dwordValue;
  10952. ctx->type.SetConstantDW(lctx->type.dataType, v);
  10953. }
  10954. else
  10955. {
  10956. asQWORD v = 0;
  10957. if( op == ttBitShiftLeft )
  10958. v = lctx->type.qwordValue << rctx->type.dwordValue;
  10959. else if( op == ttBitShiftRight )
  10960. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  10961. else if( op == ttBitShiftRightArith )
  10962. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  10963. ctx->type.SetConstantQW(lctx->type.dataType, v);
  10964. }
  10965. }
  10966. }
  10967. }
  10968. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10969. {
  10970. // Both operands must be of the same type
  10971. // If either operand is a non-primitive then first convert them to the best number type
  10972. if( !lctx->type.dataType.IsPrimitive() )
  10973. ImplicitConvObjectToBestMathType(lctx, node);
  10974. if( !rctx->type.dataType.IsPrimitive() )
  10975. ImplicitConvObjectToBestMathType(rctx, node);
  10976. // Implicitly convert the operands to matching types
  10977. asCDataType to;
  10978. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  10979. to.SetTokenType(ttDouble);
  10980. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  10981. to.SetTokenType(ttFloat);
  10982. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10983. {
  10984. // Convert to int64 if both are signed or if one is non-constant and signed
  10985. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10986. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10987. to.SetTokenType(ttInt64);
  10988. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10989. to.SetTokenType(ttUInt64);
  10990. else
  10991. to.SetTokenType(ttInt64);
  10992. }
  10993. else
  10994. {
  10995. // Convert to int32 if both are signed or if one is non-constant and signed
  10996. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10997. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10998. to.SetTokenType(ttInt);
  10999. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11000. to.SetTokenType(ttUInt);
  11001. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  11002. to.SetTokenType(ttBool);
  11003. else
  11004. to.SetTokenType(ttInt);
  11005. }
  11006. // If doing an operation with double constant and float variable, the constant should be converted to float
  11007. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  11008. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  11009. to.SetTokenType(ttFloat);
  11010. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  11011. // Do we have a mismatch between the sign of the operand?
  11012. bool signMismatch = false;
  11013. for( int n = 0; !signMismatch && n < 2; n++ )
  11014. {
  11015. asSExprContext *op = n ? rctx : lctx;
  11016. if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  11017. {
  11018. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  11019. signMismatch = true;
  11020. if( op->type.isConstant )
  11021. {
  11022. if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
  11023. {
  11024. if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
  11025. signMismatch = false;
  11026. }
  11027. else
  11028. {
  11029. if( !(op->type.dwordValue & (1<<31)) )
  11030. signMismatch = false;
  11031. }
  11032. // It's not necessary to check for floats or double, because if
  11033. // it was then the types for the conversion will never be unsigned
  11034. }
  11035. }
  11036. }
  11037. // Check for signed/unsigned mismatch
  11038. if( signMismatch )
  11039. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  11040. // Do the actual conversion
  11041. int l = int(reservedVariables.GetLength());
  11042. rctx->bc.GetVarsUsed(reservedVariables);
  11043. if( lctx->type.dataType.IsReference() )
  11044. ConvertToVariable(lctx);
  11045. if( rctx->type.dataType.IsReference() )
  11046. ConvertToVariable(rctx);
  11047. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  11048. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  11049. reservedVariables.SetLength(l);
  11050. // Verify that the conversion was successful
  11051. bool ok = true;
  11052. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  11053. {
  11054. asCString str;
  11055. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  11056. Error(str, node);
  11057. ok = false;
  11058. }
  11059. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  11060. {
  11061. asCString str;
  11062. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  11063. Error(str, node);
  11064. ok = false;
  11065. }
  11066. if( !ok )
  11067. {
  11068. // It wasn't possible to get two valid operands, so we just return
  11069. // a boolean result and let the compiler continue.
  11070. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11071. return;
  11072. }
  11073. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11074. int op = node->tokenType;
  11075. if( !isConstant )
  11076. {
  11077. if( to.IsBooleanType() )
  11078. {
  11079. int op = node->tokenType;
  11080. if( op == ttEqual || op == ttNotEqual )
  11081. {
  11082. // Must convert to temporary variable, because we are changing the value before comparison
  11083. ConvertToTempVariableNotIn(lctx, rctx);
  11084. ConvertToTempVariableNotIn(rctx, lctx);
  11085. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11086. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11087. // Make sure they are equal if not false
  11088. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  11089. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  11090. MergeExprBytecode(ctx, lctx);
  11091. MergeExprBytecode(ctx, rctx);
  11092. ProcessDeferredParams(ctx);
  11093. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  11094. int b = lctx->type.stackOffset;
  11095. int c = rctx->type.stackOffset;
  11096. if( op == ttEqual )
  11097. {
  11098. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  11099. ctx->bc.Instr(asBC_TZ);
  11100. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11101. }
  11102. else if( op == ttNotEqual )
  11103. {
  11104. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  11105. ctx->bc.Instr(asBC_TNZ);
  11106. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11107. }
  11108. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11109. }
  11110. else
  11111. {
  11112. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  11113. Error(TXT_ILLEGAL_OPERATION, node);
  11114. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  11115. }
  11116. }
  11117. else
  11118. {
  11119. ConvertToVariableNotIn(lctx, rctx);
  11120. ConvertToVariableNotIn(rctx, lctx);
  11121. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11122. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11123. MergeExprBytecode(ctx, lctx);
  11124. MergeExprBytecode(ctx, rctx);
  11125. ProcessDeferredParams(ctx);
  11126. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  11127. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11128. iCmp = asBC_CMPi;
  11129. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11130. iCmp = asBC_CMPu;
  11131. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11132. iCmp = asBC_CMPi64;
  11133. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11134. iCmp = asBC_CMPu64;
  11135. else if( lctx->type.dataType.IsFloatType() )
  11136. iCmp = asBC_CMPf;
  11137. else if( lctx->type.dataType.IsDoubleType() )
  11138. iCmp = asBC_CMPd;
  11139. else
  11140. asASSERT(false);
  11141. if( op == ttEqual )
  11142. iT = asBC_TZ;
  11143. else if( op == ttNotEqual )
  11144. iT = asBC_TNZ;
  11145. else if( op == ttLessThan )
  11146. iT = asBC_TS;
  11147. else if( op == ttLessThanOrEqual )
  11148. iT = asBC_TNP;
  11149. else if( op == ttGreaterThan )
  11150. iT = asBC_TP;
  11151. else if( op == ttGreaterThanOrEqual )
  11152. iT = asBC_TNS;
  11153. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  11154. int b = lctx->type.stackOffset;
  11155. int c = rctx->type.stackOffset;
  11156. ctx->bc.InstrW_W(iCmp, b, c);
  11157. ctx->bc.Instr(iT);
  11158. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11159. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11160. }
  11161. }
  11162. else
  11163. {
  11164. if( to.IsBooleanType() )
  11165. {
  11166. int op = node->tokenType;
  11167. if( op == ttEqual || op == ttNotEqual )
  11168. {
  11169. // Make sure they are equal if not false
  11170. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11171. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11172. asDWORD v = 0;
  11173. if( op == ttEqual )
  11174. {
  11175. v = lctx->type.intValue - rctx->type.intValue;
  11176. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11177. }
  11178. else if( op == ttNotEqual )
  11179. {
  11180. v = lctx->type.intValue - rctx->type.intValue;
  11181. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11182. }
  11183. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  11184. }
  11185. else
  11186. {
  11187. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  11188. Error(TXT_ILLEGAL_OPERATION, node);
  11189. }
  11190. }
  11191. else
  11192. {
  11193. int i = 0;
  11194. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11195. {
  11196. int v = lctx->type.intValue - rctx->type.intValue;
  11197. if( v < 0 ) i = -1;
  11198. if( v > 0 ) i = 1;
  11199. }
  11200. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11201. {
  11202. asDWORD v1 = lctx->type.dwordValue;
  11203. asDWORD v2 = rctx->type.dwordValue;
  11204. if( v1 < v2 ) i = -1;
  11205. if( v1 > v2 ) i = 1;
  11206. }
  11207. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11208. {
  11209. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  11210. if( v < 0 ) i = -1;
  11211. if( v > 0 ) i = 1;
  11212. }
  11213. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11214. {
  11215. asQWORD v1 = lctx->type.qwordValue;
  11216. asQWORD v2 = rctx->type.qwordValue;
  11217. if( v1 < v2 ) i = -1;
  11218. if( v1 > v2 ) i = 1;
  11219. }
  11220. else if( lctx->type.dataType.IsFloatType() )
  11221. {
  11222. float v = lctx->type.floatValue - rctx->type.floatValue;
  11223. if( v < 0 ) i = -1;
  11224. if( v > 0 ) i = 1;
  11225. }
  11226. else if( lctx->type.dataType.IsDoubleType() )
  11227. {
  11228. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  11229. if( v < 0 ) i = -1;
  11230. if( v > 0 ) i = 1;
  11231. }
  11232. if( op == ttEqual )
  11233. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11234. else if( op == ttNotEqual )
  11235. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11236. else if( op == ttLessThan )
  11237. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11238. else if( op == ttLessThanOrEqual )
  11239. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11240. else if( op == ttGreaterThan )
  11241. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11242. else if( op == ttGreaterThanOrEqual )
  11243. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  11244. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  11245. }
  11246. }
  11247. }
  11248. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  11249. {
  11250. // Put the result on the stack
  11251. if( asReference )
  11252. {
  11253. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  11254. ctx->type.dataType.MakeReference(true);
  11255. }
  11256. else
  11257. {
  11258. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11259. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  11260. else
  11261. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  11262. }
  11263. }
  11264. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  11265. {
  11266. // Both operands must be booleans
  11267. asCDataType to;
  11268. to.SetTokenType(ttBool);
  11269. // Do the actual conversion
  11270. int l = int(reservedVariables.GetLength());
  11271. rctx->bc.GetVarsUsed(reservedVariables);
  11272. lctx->bc.GetVarsUsed(reservedVariables);
  11273. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  11274. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  11275. reservedVariables.SetLength(l);
  11276. // Verify that the conversion was successful
  11277. if( !lctx->type.dataType.IsBooleanType() )
  11278. {
  11279. asCString str;
  11280. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  11281. Error(str, node);
  11282. // Force the conversion to allow compilation to proceed
  11283. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11284. }
  11285. if( !rctx->type.dataType.IsBooleanType() )
  11286. {
  11287. asCString str;
  11288. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  11289. Error(str, node);
  11290. // Force the conversion to allow compilation to proceed
  11291. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11292. }
  11293. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11294. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  11295. // What kind of operator is it?
  11296. int op = node->tokenType;
  11297. if( op == ttXor )
  11298. {
  11299. if( !isConstant )
  11300. {
  11301. // Must convert to temporary variable, because we are changing the value before comparison
  11302. ConvertToTempVariableNotIn(lctx, rctx);
  11303. ConvertToTempVariableNotIn(rctx, lctx);
  11304. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11305. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11306. // Make sure they are equal if not false
  11307. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  11308. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  11309. MergeExprBytecode(ctx, lctx);
  11310. MergeExprBytecode(ctx, rctx);
  11311. ProcessDeferredParams(ctx);
  11312. int a = AllocateVariable(ctx->type.dataType, true);
  11313. int b = lctx->type.stackOffset;
  11314. int c = rctx->type.stackOffset;
  11315. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  11316. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11317. }
  11318. else
  11319. {
  11320. // Make sure they are equal if not false
  11321. #if AS_SIZEOF_BOOL == 1
  11322. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  11323. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  11324. asBYTE v = 0;
  11325. v = lctx->type.byteValue - rctx->type.byteValue;
  11326. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11327. ctx->type.isConstant = true;
  11328. ctx->type.byteValue = v;
  11329. #else
  11330. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11331. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  11332. asDWORD v = 0;
  11333. v = lctx->type.intValue - rctx->type.intValue;
  11334. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  11335. ctx->type.isConstant = true;
  11336. ctx->type.dwordValue = v;
  11337. #endif
  11338. }
  11339. }
  11340. else if( op == ttAnd ||
  11341. op == ttOr )
  11342. {
  11343. if( !isConstant )
  11344. {
  11345. // If or-operator and first value is 1 the second value shouldn't be calculated
  11346. // if and-operator and first value is 0 the second value shouldn't be calculated
  11347. ConvertToVariable(lctx);
  11348. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11349. MergeExprBytecode(ctx, lctx);
  11350. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11351. int label1 = nextLabel++;
  11352. int label2 = nextLabel++;
  11353. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  11354. ctx->bc.Instr(asBC_ClrHi);
  11355. if( op == ttAnd )
  11356. {
  11357. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  11358. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  11359. ctx->bc.InstrINT(asBC_JMP, label2);
  11360. }
  11361. else if( op == ttOr )
  11362. {
  11363. ctx->bc.InstrDWORD(asBC_JZ, label1);
  11364. #if AS_SIZEOF_BOOL == 1
  11365. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  11366. #else
  11367. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  11368. #endif
  11369. ctx->bc.InstrINT(asBC_JMP, label2);
  11370. }
  11371. ctx->bc.Label((short)label1);
  11372. ConvertToVariable(rctx);
  11373. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11374. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  11375. MergeExprBytecode(ctx, rctx);
  11376. ctx->bc.Label((short)label2);
  11377. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  11378. }
  11379. else
  11380. {
  11381. #if AS_SIZEOF_BOOL == 1
  11382. asBYTE v = 0;
  11383. if( op == ttAnd )
  11384. v = lctx->type.byteValue && rctx->type.byteValue;
  11385. else if( op == ttOr )
  11386. v = lctx->type.byteValue || rctx->type.byteValue;
  11387. // Remember the result
  11388. ctx->type.isConstant = true;
  11389. ctx->type.byteValue = v;
  11390. #else
  11391. asDWORD v = 0;
  11392. if( op == ttAnd )
  11393. v = lctx->type.dwordValue && rctx->type.dwordValue;
  11394. else if( op == ttOr )
  11395. v = lctx->type.dwordValue || rctx->type.dwordValue;
  11396. // Remember the result
  11397. ctx->type.isConstant = true;
  11398. ctx->type.dwordValue = v;
  11399. #endif
  11400. }
  11401. }
  11402. }
  11403. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  11404. {
  11405. // Process the property accessor as get
  11406. ProcessPropertyGetAccessor(lctx, node);
  11407. ProcessPropertyGetAccessor(rctx, node);
  11408. DetermineSingleFunc(lctx, node);
  11409. DetermineSingleFunc(rctx, node);
  11410. // Make sure lctx doesn't end up with a variable used in rctx
  11411. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  11412. {
  11413. asCArray<int> vars;
  11414. rctx->bc.GetVarsUsed(vars);
  11415. int offset = AllocateVariable(lctx->type.dataType, true);
  11416. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  11417. ReleaseTemporaryVariable(offset, 0);
  11418. }
  11419. // Warn if not both operands are explicit handles or null handles
  11420. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  11421. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  11422. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  11423. {
  11424. Warning(TXT_HANDLE_COMPARISON, node);
  11425. }
  11426. // If one of the operands is a value type used as handle, we should look for the opEquals method
  11427. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  11428. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  11429. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  11430. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  11431. {
  11432. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11433. // Find the matching opEquals method
  11434. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11435. if( r == 0 )
  11436. {
  11437. // Try again by switching the order of the operands
  11438. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11439. }
  11440. if( r == 1 )
  11441. {
  11442. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  11443. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  11444. // Success, don't continue
  11445. return;
  11446. }
  11447. else if( r == 0 )
  11448. {
  11449. // Couldn't find opEquals method
  11450. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  11451. }
  11452. // Compiler error, don't continue
  11453. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11454. return;
  11455. }
  11456. // Implicitly convert null to the other type
  11457. asCDataType to;
  11458. if( lctx->type.IsNullConstant() )
  11459. to = rctx->type.dataType;
  11460. else if( rctx->type.IsNullConstant() )
  11461. to = lctx->type.dataType;
  11462. else
  11463. {
  11464. // Find a common base type
  11465. asSExprContext tmp(engine);
  11466. tmp.type = rctx->type;
  11467. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  11468. if( tmp.type.dataType.GetObjectType() == lctx->type.dataType.GetObjectType() )
  11469. to = lctx->type.dataType;
  11470. else
  11471. to = rctx->type.dataType;
  11472. }
  11473. // Need to pop the value if it is a null constant
  11474. if( lctx->type.IsNullConstant() )
  11475. lctx->bc.Instr(asBC_PopPtr);
  11476. if( rctx->type.IsNullConstant() )
  11477. rctx->bc.Instr(asBC_PopPtr);
  11478. // Convert both sides to explicit handles
  11479. to.MakeHandle(true);
  11480. to.MakeReference(false);
  11481. if( !to.IsObjectHandle() )
  11482. {
  11483. // Compiler error, don't continue
  11484. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  11485. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11486. return;
  11487. }
  11488. // Do the conversion
  11489. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  11490. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  11491. // Both operands must be of the same type
  11492. // Verify that the conversion was successful
  11493. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  11494. {
  11495. asCString str;
  11496. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  11497. Error(str, node);
  11498. }
  11499. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  11500. {
  11501. asCString str;
  11502. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  11503. Error(str, node);
  11504. }
  11505. // Make sure it really is handles that are being compared
  11506. if( !lctx->type.dataType.IsObjectHandle() )
  11507. {
  11508. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  11509. }
  11510. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  11511. int op = node->tokenType;
  11512. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  11513. {
  11514. // TODO: runtime optimize: don't do REFCPY
  11515. ConvertToVariableNotIn(lctx, rctx);
  11516. ConvertToVariable(rctx);
  11517. // Pop the pointers from the stack as they will not be used
  11518. lctx->bc.Instr(asBC_PopPtr);
  11519. rctx->bc.Instr(asBC_PopPtr);
  11520. MergeExprBytecode(ctx, lctx);
  11521. MergeExprBytecode(ctx, rctx);
  11522. int a = AllocateVariable(ctx->type.dataType, true);
  11523. int b = lctx->type.stackOffset;
  11524. int c = rctx->type.stackOffset;
  11525. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  11526. if( op == ttEqual || op == ttIs )
  11527. ctx->bc.Instr(asBC_TZ);
  11528. else if( op == ttNotEqual || op == ttNotIs )
  11529. ctx->bc.Instr(asBC_TNZ);
  11530. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11531. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  11532. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  11533. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  11534. ProcessDeferredParams(ctx);
  11535. }
  11536. else
  11537. {
  11538. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  11539. Error(TXT_ILLEGAL_OPERATION, node);
  11540. }
  11541. }
  11542. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  11543. {
  11544. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  11545. // A shared object may not call non-shared functions
  11546. if( outFunc->IsShared() && !descr->IsShared() )
  11547. {
  11548. asCString msg;
  11549. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  11550. Error(msg, ctx->exprNode);
  11551. }
  11552. // Check if the function is private
  11553. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  11554. {
  11555. asCString msg;
  11556. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  11557. Error(msg, ctx->exprNode);
  11558. }
  11559. int argSize = descr->GetSpaceNeededForArguments();
  11560. // If we're calling a class method we must make sure the object is guaranteed to stay
  11561. // alive throughout the call by holding on to a reference in a local variable. This must
  11562. // be done for any methods that return references, and any calls on script objects.
  11563. // Application registered objects are assumed to know to keep themselves alive even
  11564. // if the method doesn't return a refernce.
  11565. if( descr->objectType &&
  11566. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  11567. (descr->returnType.IsReference() || (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  11568. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  11569. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  11570. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  11571. {
  11572. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  11573. int tempRef = AllocateVariable(ctx->type.dataType, true);
  11574. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  11575. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  11576. // Add the release of this reference as a deferred expression
  11577. asSDeferredParam deferred;
  11578. deferred.origExpr = 0;
  11579. deferred.argInOutFlags = asTM_INREF;
  11580. deferred.argNode = 0;
  11581. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  11582. ctx->deferredParams.PushLast(deferred);
  11583. // Forget the current type
  11584. ctx->type.SetDummy();
  11585. }
  11586. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  11587. if( descr->DoesReturnOnStack() && !useVariable )
  11588. {
  11589. useVariable = true;
  11590. varOffset = AllocateVariable(descr->returnType, true);
  11591. // Push the pointer to the pre-allocated space for the return value
  11592. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  11593. if( descr->objectType )
  11594. {
  11595. // The object pointer is already on the stack, but should be the top
  11596. // one, so we need to swap the pointers in order to get the correct
  11597. ctx->bc.Instr(asBC_SwapPtr);
  11598. }
  11599. }
  11600. if( isConstructor )
  11601. {
  11602. // Sometimes the value types are allocated on the heap,
  11603. // which is when this way of constructing them is used.
  11604. asASSERT(useVariable == false);
  11605. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  11606. // The instruction has already moved the returned object to the variable
  11607. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  11608. ctx->type.isLValue = false;
  11609. // Clean up arguments
  11610. if( args )
  11611. AfterFunctionCall(funcId, *args, ctx, false);
  11612. ProcessDeferredParams(ctx);
  11613. return;
  11614. }
  11615. else
  11616. {
  11617. if( descr->objectType )
  11618. argSize += AS_PTR_SIZE;
  11619. // If the function returns an object by value the address of the location
  11620. // where the value should be stored is passed as an argument too
  11621. if( descr->DoesReturnOnStack() )
  11622. argSize += AS_PTR_SIZE;
  11623. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  11624. // should be made with asBC_CALL as it is faster. Examples where this
  11625. // is known is for example finalled methods where the class doesn't derive
  11626. // from any other, or even non-finalled methods but where it is known
  11627. // at compile time the true type of the object. The first should be
  11628. // quite easy to determine, but the latter will be quite complex and possibly
  11629. // not worth it.
  11630. if( descr->funcType == asFUNC_IMPORTED )
  11631. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  11632. // TODO: Maybe we need two different byte codes
  11633. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  11634. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  11635. else if( descr->funcType == asFUNC_SCRIPT )
  11636. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  11637. else if( descr->funcType == asFUNC_SYSTEM )
  11638. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  11639. else if( descr->funcType == asFUNC_FUNCDEF )
  11640. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  11641. }
  11642. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  11643. {
  11644. int returnOffset = 0;
  11645. asCTypeInfo tmpExpr = ctx->type;
  11646. if( descr->DoesReturnOnStack() )
  11647. {
  11648. asASSERT( useVariable );
  11649. // The variable was allocated before the function was called
  11650. returnOffset = varOffset;
  11651. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  11652. // The variable was initialized by the function, so we need to mark it as initialized here
  11653. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  11654. }
  11655. else
  11656. {
  11657. if( useVariable )
  11658. {
  11659. // Use the given variable
  11660. returnOffset = varOffset;
  11661. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  11662. }
  11663. else
  11664. {
  11665. // Allocate a temporary variable for the returned object
  11666. // The returned object will actually be allocated on the heap, so
  11667. // we must force the allocation of the variable to do the same
  11668. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  11669. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  11670. }
  11671. // Move the pointer from the object register to the temporary variable
  11672. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  11673. }
  11674. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  11675. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  11676. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  11677. // Clean up arguments
  11678. if( args )
  11679. AfterFunctionCall(funcId, *args, ctx, false);
  11680. ProcessDeferredParams(ctx);
  11681. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  11682. }
  11683. else if( descr->returnType.IsReference() )
  11684. {
  11685. asASSERT(useVariable == false);
  11686. // We cannot clean up the arguments yet, because the
  11687. // reference might be pointing to one of them.
  11688. if( args )
  11689. AfterFunctionCall(funcId, *args, ctx, true);
  11690. // Do not process the output parameters yet, because it
  11691. // might invalidate the returned reference
  11692. // If the context holds a variable that needs cleanup
  11693. // store it as a deferred parameter so it will be cleaned up
  11694. // afterwards.
  11695. if( ctx->type.isTemporary )
  11696. {
  11697. asSDeferredParam defer;
  11698. defer.argNode = 0;
  11699. defer.argType = ctx->type;
  11700. defer.argInOutFlags = asTM_INOUTREF;
  11701. defer.origExpr = 0;
  11702. ctx->deferredParams.PushLast(defer);
  11703. }
  11704. ctx->type.Set(descr->returnType);
  11705. if( !descr->returnType.IsPrimitive() )
  11706. {
  11707. ctx->bc.Instr(asBC_PshRPtr);
  11708. if( descr->returnType.IsObject() &&
  11709. !descr->returnType.IsObjectHandle() )
  11710. {
  11711. // We are getting the pointer to the object
  11712. // not a pointer to a object variable
  11713. ctx->type.dataType.MakeReference(false);
  11714. }
  11715. }
  11716. // A returned reference can be used as lvalue
  11717. ctx->type.isLValue = true;
  11718. }
  11719. else
  11720. {
  11721. asASSERT(useVariable == false);
  11722. asCTypeInfo tmpExpr = ctx->type;
  11723. if( descr->returnType.GetSizeInMemoryBytes() )
  11724. {
  11725. // Allocate a temporary variable to hold the value, but make sure
  11726. // the temporary variable isn't used in any of the deferred arguments
  11727. int l = int(reservedVariables.GetLength());
  11728. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  11729. {
  11730. asSExprContext *expr = (*args)[n]->origExpr;
  11731. if( expr )
  11732. expr->bc.GetVarsUsed(reservedVariables);
  11733. }
  11734. int offset = AllocateVariable(descr->returnType, true);
  11735. reservedVariables.SetLength(l);
  11736. ctx->type.SetVariable(descr->returnType, offset, true);
  11737. // Move the value from the return register to the variable
  11738. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  11739. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  11740. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  11741. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  11742. }
  11743. else
  11744. ctx->type.Set(descr->returnType);
  11745. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  11746. ctx->type.isLValue = false;
  11747. // Clean up arguments
  11748. if( args )
  11749. AfterFunctionCall(funcId, *args, ctx, false);
  11750. ProcessDeferredParams(ctx);
  11751. }
  11752. }
  11753. // This only merges the bytecode, but doesn't modify the type of the final context
  11754. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  11755. {
  11756. before->bc.AddCode(&after->bc);
  11757. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  11758. {
  11759. before->deferredParams.PushLast(after->deferredParams[n]);
  11760. after->deferredParams[n].origExpr = 0;
  11761. }
  11762. after->deferredParams.SetLength(0);
  11763. }
  11764. // This merges both bytecode and the type of the final context
  11765. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  11766. {
  11767. MergeExprBytecode(before, after);
  11768. before->type = after->type;
  11769. before->property_get = after->property_get;
  11770. before->property_set = after->property_set;
  11771. before->property_const = after->property_const;
  11772. before->property_handle = after->property_handle;
  11773. before->property_ref = after->property_ref;
  11774. before->property_arg = after->property_arg;
  11775. before->exprNode = after->exprNode;
  11776. before->methodName = after->methodName;
  11777. before->enumValue = after->enumValue;
  11778. after->property_arg = 0;
  11779. // Do not copy the origExpr member
  11780. }
  11781. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  11782. {
  11783. if( funcs.GetLength() == 0 ) return;
  11784. // This is only done for object methods
  11785. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  11786. if( desc->objectType == 0 ) return;
  11787. // Check if there are any non-const matches
  11788. asUINT n;
  11789. bool foundNonConst = false;
  11790. for( n = 0; n < funcs.GetLength(); n++ )
  11791. {
  11792. desc = builder->GetFunctionDescription(funcs[n]);
  11793. if( desc->isReadOnly != removeConst )
  11794. {
  11795. foundNonConst = true;
  11796. break;
  11797. }
  11798. }
  11799. if( foundNonConst )
  11800. {
  11801. // Remove all const methods
  11802. for( n = 0; n < funcs.GetLength(); n++ )
  11803. {
  11804. desc = builder->GetFunctionDescription(funcs[n]);
  11805. if( desc->isReadOnly == removeConst )
  11806. {
  11807. if( n == funcs.GetLength() - 1 )
  11808. funcs.PopLast();
  11809. else
  11810. funcs[n] = funcs.PopLast();
  11811. n--;
  11812. }
  11813. }
  11814. }
  11815. }
  11816. END_AS_NAMESPACE
  11817. #endif // AS_NO_COMPILER