as_compiler.cpp 359 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2012 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 Öörni 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()
  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. BEGIN_AS_NAMESPACE
  39. //
  40. // The calling convention rules for script functions:
  41. // - 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
  42. // - 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
  43. // - The object pointer is always passed as the first argument, position 0
  44. // - 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
  45. //
  46. // TODO: I must correct the interpretation of a references to objects in the compiler.
  47. // A reference should mean that a pointer to the object is on the stack.
  48. // No expression should end up as non-references to objects, as the actual object is
  49. // never put on the stack.
  50. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  51. // Function parameters of called functions can also be non-references, but in that case it means the
  52. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  53. //
  54. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  55. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  56. // is currently stored, i.e. in variable, in register, on stack, etc.
  57. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  58. {
  59. builder = 0;
  60. script = 0;
  61. variables = 0;
  62. isProcessingDeferredParams = false;
  63. isCompilingDefaultArg = false;
  64. noCodeOutput = 0;
  65. }
  66. asCCompiler::~asCCompiler()
  67. {
  68. while( variables )
  69. {
  70. asCVariableScope *var = variables;
  71. variables = variables->parent;
  72. asDELETE(var,asCVariableScope);
  73. }
  74. }
  75. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  76. {
  77. this->builder = builder;
  78. this->engine = builder->engine;
  79. this->script = script;
  80. this->outFunc = outFunc;
  81. hasCompileErrors = false;
  82. m_isConstructor = false;
  83. m_isConstructorCalled = false;
  84. nextLabel = 0;
  85. breakLabels.SetLength(0);
  86. continueLabels.SetLength(0);
  87. byteCode.ClearAll();
  88. }
  89. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc)
  90. {
  91. Reset(builder, script, outFunc);
  92. // Make sure all the class members can be initialized with default constructors
  93. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  94. {
  95. asCDataType &dt = outFunc->objectType->properties[n]->type;
  96. if( dt.IsObject() && !dt.IsObjectHandle() &&
  97. (((dt.GetObjectType()->flags & asOBJ_REF) && dt.GetObjectType()->beh.factory == 0) ||
  98. ((dt.GetObjectType()->flags & asOBJ_VALUE) && !(dt.GetObjectType()->flags & asOBJ_POD) && dt.GetObjectType()->beh.construct == 0)) )
  99. {
  100. asCString str;
  101. if( dt.GetFuncDef() )
  102. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  103. else
  104. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  105. Error(str.AddressOf(), node);
  106. }
  107. }
  108. // If the class is derived from another, then the base class' default constructor must be called
  109. if( outFunc->objectType->derivedFrom )
  110. {
  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. // Pop the object pointer from the stack
  117. byteCode.Ret(AS_PTR_SIZE);
  118. FinalizeFunction();
  119. #ifdef AS_DEBUG
  120. // DEBUG: output byte code
  121. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__dc.txt").AddressOf(), engine, outFunc);
  122. #endif
  123. return 0;
  124. }
  125. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  126. {
  127. Reset(builder, script, outFunc);
  128. unsigned int n;
  129. // Find the corresponding constructor
  130. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  131. int constructor = 0;
  132. for( n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  133. {
  134. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  135. {
  136. constructor = dt.GetBehaviour()->constructors[n];
  137. break;
  138. }
  139. }
  140. // Allocate the class and instanciate it with the constructor
  141. int varOffset = AllocateVariable(dt, true);
  142. outFunc->variableSpace = AS_PTR_SIZE;
  143. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  144. // Copy all arguments to the top of the stack
  145. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  146. int offset = (int)outFunc->GetSpaceNeededForArguments();
  147. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  148. {
  149. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  150. outFunc->parameterTypes[a].IsReference() )
  151. {
  152. offset -= AS_PTR_SIZE;
  153. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  154. }
  155. else
  156. {
  157. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  158. {
  159. offset -= 2;
  160. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  161. }
  162. else
  163. {
  164. offset -= 1;
  165. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  166. }
  167. }
  168. }
  169. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  170. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  171. // Return a handle to the newly created object
  172. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  173. byteCode.Ret(argDwords);
  174. FinalizeFunction();
  175. // Tell the virtual machine not to clean up parameters on exception
  176. outFunc->dontCleanUpOnException = true;
  177. /*
  178. #ifdef AS_DEBUG
  179. // DEBUG: output byte code
  180. asCString args;
  181. args.Format("%d", outFunc->parameterTypes.GetLength());
  182. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  183. #endif
  184. */
  185. return 0;
  186. }
  187. void asCCompiler::FinalizeFunction()
  188. {
  189. asUINT n;
  190. // Tell the bytecode which variables are temporary
  191. for( n = 0; n < variableIsTemporary.GetLength(); n++ )
  192. {
  193. if( variableIsTemporary[n] )
  194. byteCode.DefineTemporaryVariable(GetVariableOffset(n));
  195. }
  196. // Finalize the bytecode
  197. byteCode.Finalize();
  198. byteCode.ExtractObjectVariableInfo(outFunc);
  199. // Compile the list of object variables for the exception handler
  200. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  201. for( n = 0; n < variableAllocations.GetLength(); n++ )
  202. {
  203. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  204. {
  205. if( variableIsOnHeap[n] )
  206. {
  207. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  208. outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  209. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  210. }
  211. }
  212. }
  213. outFunc->objVariablesOnHeap = outFunc->objVariablePos.GetLength();
  214. for( n = 0; n < variableAllocations.GetLength(); n++ )
  215. {
  216. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  217. {
  218. if( !variableIsOnHeap[n] )
  219. {
  220. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  221. outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  222. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  223. }
  224. }
  225. }
  226. // Copy byte code to the function
  227. outFunc->byteCode.SetLength(byteCode.GetSize());
  228. byteCode.Output(outFunc->byteCode.AddressOf());
  229. outFunc->AddReferences();
  230. outFunc->stackNeeded = byteCode.largestStackUsed + outFunc->variableSpace;
  231. outFunc->lineNumbers = byteCode.lineNumbers;
  232. }
  233. // Entry
  234. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, sExplicitSignature *signature, asCScriptNode *func, asCScriptFunction *outFunc)
  235. {
  236. // TODO: The compiler should take the return type and parameter types from the
  237. // outFunc, instead of interpreting the script nodes again. The builder
  238. // must pass the list of parameter names. Making this change we can
  239. // eliminate large parts of this function and the sExplicitSignature structure
  240. Reset(builder, script, outFunc);
  241. int buildErrors = builder->numErrors;
  242. int stackPos = 0;
  243. if( outFunc->objectType )
  244. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  245. // Reserve a label for the cleanup code
  246. nextLabel++;
  247. // Add the first variable scope, which the parameters and
  248. // variables declared in the outermost statement block is
  249. // part of.
  250. AddVariableScope();
  251. asCScriptNode *node;
  252. bool isDestructor = false;
  253. asCDataType returnType;
  254. if( !signature )
  255. {
  256. node = func->firstChild;
  257. if( outFunc->objectType )
  258. {
  259. // Skip the private keyword if it is there
  260. if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
  261. node = node->next;
  262. }
  263. else if( outFunc->IsShared() )
  264. {
  265. // Skip the shared keyword
  266. asASSERT( node->nodeType == snIdentifier );
  267. node = node->next;
  268. }
  269. //----------------------------------------------
  270. // Examine return type
  271. if( node->nodeType == snDataType )
  272. {
  273. // TODO: namespace: Use correct implicit namespace from function
  274. returnType = builder->CreateDataTypeFromNode(node, script, "");
  275. returnType = builder->ModifyDataTypeFromNode(returnType, node->next, script, 0, 0);
  276. // Make sure the return type is instanciable or is void
  277. if( !returnType.CanBeInstanciated() &&
  278. returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  279. {
  280. asCString str;
  281. str.Format(TXT_DATA_TYPE_CANT_BE_s, returnType.Format().AddressOf());
  282. Error(str.AddressOf(), func->firstChild);
  283. }
  284. }
  285. else
  286. {
  287. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  288. if( node->tokenType == ttBitNot )
  289. isDestructor = true;
  290. else
  291. m_isConstructor = true;
  292. }
  293. }
  294. else
  295. {
  296. node = func;
  297. returnType = signature->returnType;
  298. }
  299. // If the return type is a value type returned by value the address of the
  300. // location where the value will be stored is pushed on the stack before
  301. // the arguments
  302. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  303. stackPos -= AS_PTR_SIZE;
  304. asCVariableScope vs(0);
  305. if( !signature )
  306. {
  307. //----------------------------------------------
  308. // Declare parameters
  309. // Find first parameter
  310. while( node && node->nodeType != snParameterList )
  311. node = node->next;
  312. // Register parameters from last to first, otherwise they will be destroyed in the wrong order
  313. if( node ) node = node->firstChild;
  314. while( node )
  315. {
  316. // Get the parameter type
  317. // TODO: namespace: Use correct implicit namespace from function
  318. asCDataType type = builder->CreateDataTypeFromNode(node, script, "");
  319. asETypeModifiers inoutFlag = asTM_NONE;
  320. type = builder->ModifyDataTypeFromNode(type, node->next, script, &inoutFlag, 0);
  321. // Is the data type allowed?
  322. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  323. (!type.IsReference() && !type.CanBeInstanciated()) )
  324. {
  325. asCString parm = type.Format();
  326. if( inoutFlag == asTM_INREF )
  327. parm += "in";
  328. else if( inoutFlag == asTM_OUTREF )
  329. parm += "out";
  330. asCString str;
  331. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  332. Error(str.AddressOf(), node);
  333. }
  334. // If the parameter has a name then declare it as variable
  335. node = node->next->next;
  336. if( node && node->nodeType == snIdentifier )
  337. {
  338. asCString name(&script->code[node->tokenPos], node->tokenLength);
  339. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  340. {
  341. // TODO: It might be an out-of-memory too
  342. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  343. }
  344. // Add marker for variable declaration
  345. byteCode.VarDecl((int)outFunc->variables.GetLength());
  346. outFunc->AddVariable(name, type, stackPos);
  347. node = node->next;
  348. // Skip the default arg
  349. if( node && node->nodeType == snExpression )
  350. node = node->next;
  351. }
  352. else
  353. vs.DeclareVariable("", type, stackPos, true);
  354. // Move to next parameter
  355. stackPos -= type.GetSizeOnStackDWords();
  356. }
  357. }
  358. else
  359. {
  360. asCArray<asCDataType> &args = signature->argTypes;
  361. asCArray<asETypeModifiers> &inoutFlags = signature->argModifiers;
  362. asCArray<asCString> &argNames = signature->argNames;
  363. asASSERT(args.GetLength() == argNames.GetLength());
  364. for( int k = 0; k < (int)args.GetLength(); k++ )
  365. {
  366. asCDataType type = args[k];
  367. asETypeModifiers inoutFlag = inoutFlags[k];
  368. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  369. (!type.IsReference() && !type.CanBeInstanciated()) )
  370. {
  371. asCString str;
  372. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  373. Error(str.AddressOf(), node);
  374. }
  375. if( 0 != argNames[k].Compare("") )
  376. {
  377. if( vs.DeclareVariable(argNames[k].AddressOf(), type, stackPos, true) < 0 )
  378. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  379. // Add marker for variable declaration
  380. byteCode.VarDecl((int)outFunc->variables.GetLength());
  381. outFunc->AddVariable(argNames[k], type, stackPos);
  382. }
  383. else
  384. vs.DeclareVariable("", type, stackPos, true);
  385. // Move to next parameter
  386. stackPos -= type.GetSizeOnStackDWords();
  387. }
  388. }
  389. int n;
  390. for( n = (int)vs.variables.GetLength() - 1; n >= 0; n-- )
  391. {
  392. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  393. }
  394. // Is the return type allowed?
  395. if( (returnType.GetSizeOnStackDWords() == 0 && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  396. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  397. {
  398. asCString str;
  399. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  400. Error(str.AddressOf(), func);
  401. }
  402. variables->DeclareVariable("return", returnType, stackPos, true);
  403. //--------------------------------------------
  404. // Compile the statement block
  405. // We need to parse the statement block now
  406. asCScriptNode *blockBegin;
  407. if( !signature )
  408. blockBegin = func->lastChild;
  409. else
  410. blockBegin = func;
  411. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  412. asCParser parser(builder);
  413. int r = parser.ParseStatementBlock(script, blockBegin);
  414. if( r < 0 ) return -1;
  415. asCScriptNode *block = parser.GetScriptNode();
  416. bool hasReturn;
  417. asCByteCode bc(engine);
  418. LineInstr(&bc, blockBegin->tokenPos);
  419. CompileStatementBlock(block, false, &hasReturn, &bc);
  420. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  421. // Make sure there is a return in all paths (if not return type is void)
  422. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  423. {
  424. if( hasReturn == false )
  425. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  426. }
  427. //------------------------------------------------
  428. // Concatenate the bytecode
  429. // Insert a JitEntry at the start of the function for JIT compilers
  430. byteCode.InstrPTR(asBC_JitEntry, 0);
  431. // Count total variable size
  432. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  433. outFunc->variableSpace = varSize;
  434. if( outFunc->objectType )
  435. {
  436. // Call the base class' default constructor unless called manually in the code
  437. if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
  438. {
  439. if( outFunc->objectType->derivedFrom->beh.construct )
  440. {
  441. byteCode.InstrSHORT(asBC_PSF, 0);
  442. byteCode.Instr(asBC_RDSPtr);
  443. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  444. }
  445. else
  446. {
  447. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  448. }
  449. }
  450. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  451. if( !m_isConstructor && !outFunc->returnType.IsReference() )
  452. {
  453. // TODO: runtime optimize: If the function is trivial, i.e. doesn't access any outside functions,
  454. // then this is not necessary. If I implement this, then the function needs
  455. // to set a flag so the exception handler doesn't try to release the handle.
  456. // It is not necessary to do this for constructors, as they have no outside references that can be released anyway
  457. // It is not necessary to do this for methods that return references, as the caller is guaranteed to hold a reference to the object
  458. byteCode.InstrSHORT(asBC_PSF, 0);
  459. byteCode.Instr(asBC_RDSPtr);
  460. byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  461. }
  462. }
  463. // Add the code for the statement block
  464. byteCode.AddCode(&bc);
  465. // Deallocate all local variables
  466. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  467. {
  468. sVariable *v = variables->variables[n];
  469. if( v->stackOffset > 0 )
  470. {
  471. // Call variables destructors
  472. if( v->name != "return" && v->name != "return address" )
  473. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  474. DeallocateVariable(v->stackOffset);
  475. }
  476. }
  477. // This is the label that return statements jump to
  478. // in order to exit the function
  479. byteCode.Label(0);
  480. // Call destructors for function parameters
  481. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  482. {
  483. sVariable *v = variables->variables[n];
  484. if( v->stackOffset <= 0 )
  485. {
  486. // Call variable destructors here, for variables not yet destroyed
  487. if( v->name != "return" && v->name != "return address" )
  488. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  489. }
  490. // Do not deallocate parameters
  491. }
  492. // Release the object pointer again
  493. if( outFunc->objectType && !m_isConstructor && !outFunc->returnType.IsReference() )
  494. {
  495. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  496. }
  497. // If there are compile errors, there is no reason to build the final code
  498. if( hasCompileErrors || builder->numErrors != buildErrors )
  499. return -1;
  500. // At this point there should be no variables allocated
  501. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  502. // Remove the variable scope
  503. RemoveVariableScope();
  504. // This POP is not necessary as the return will clean up the stack frame anyway.
  505. // The bytecode optimizer would remove this POP, however by not including it here
  506. // it is guaranteed it doesn't have to be adjusted by the asCRestore class when
  507. // a types are of a different size than originally compiled for.
  508. // byteCode.Pop(varSize);
  509. byteCode.Ret(-stackPos);
  510. FinalizeFunction();
  511. #ifdef AS_DEBUG
  512. // DEBUG: output byte code
  513. if( outFunc->objectType )
  514. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  515. else
  516. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  517. #endif
  518. return 0;
  519. }
  520. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  521. {
  522. if( !type.IsObject() )
  523. return 0;
  524. // CallCopyConstructor should not be called for object handles.
  525. asASSERT( !type.IsObjectHandle() );
  526. asCArray<asSExprContext*> args;
  527. args.PushLast(arg);
  528. // The reference parameter must be pushed on the stack
  529. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  530. // Since we're calling the copy constructor, we have to trust the function to not do
  531. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  532. // copies of the argument in order to guarantee safety.
  533. if( type.GetObjectType()->flags & asOBJ_REF )
  534. {
  535. asSExprContext ctx(engine);
  536. int func = 0;
  537. asSTypeBehaviour *beh = type.GetBehaviour();
  538. if( beh ) func = beh->copyfactory;
  539. if( func > 0 )
  540. {
  541. if( !isGlobalVar )
  542. {
  543. // Call factory and store the handle in the given variable
  544. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  545. // Pop the reference left by the function call
  546. ctx.bc.Instr(asBC_PopPtr);
  547. }
  548. else
  549. {
  550. // Call factory
  551. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  552. // Store the returned handle in the global variable
  553. ctx.bc.Instr(asBC_RDSPtr);
  554. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  555. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  556. ctx.bc.Instr(asBC_PopPtr);
  557. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  558. }
  559. bc->AddCode(&ctx.bc);
  560. return 0;
  561. }
  562. }
  563. else
  564. {
  565. asSTypeBehaviour *beh = type.GetBehaviour();
  566. int func = beh ? beh->copyconstruct : 0;
  567. if( func > 0 )
  568. {
  569. // Push the address where the object will be stored on the stack, before the argument
  570. // TODO: When the context is serializable this probably has to be changed, since this
  571. // pointer can remain on the stack while the context is suspended. There is no
  572. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  573. asCByteCode tmp(engine);
  574. if( isGlobalVar )
  575. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  576. else if( isObjectOnHeap )
  577. tmp.InstrSHORT(asBC_PSF, (short)offset);
  578. tmp.AddCode(bc);
  579. bc->AddCode(&tmp);
  580. // When the object is allocated on the stack the object pointer
  581. // must be pushed on the stack after the arguments
  582. if( !isObjectOnHeap )
  583. {
  584. asASSERT( !isGlobalVar );
  585. bc->InstrSHORT(asBC_PSF, (short)offset);
  586. if( derefDest )
  587. {
  588. // The variable is a reference to the real location, so we need to dereference it
  589. bc->Instr(asBC_RDSPtr);
  590. }
  591. }
  592. asSExprContext ctx(engine);
  593. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  594. bc->AddCode(&ctx.bc);
  595. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  596. // Mark the object as initialized
  597. if( !isObjectOnHeap )
  598. bc->ObjInfo(offset, asOBJ_INIT);
  599. return 0;
  600. }
  601. }
  602. // Class has no copy constructor/factory.
  603. asCString str;
  604. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  605. Error(str.AddressOf(), node);
  606. return -1;
  607. }
  608. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, bool isGlobalVar, bool deferDest)
  609. {
  610. if( !type.IsObject() || type.IsObjectHandle() )
  611. return 0;
  612. if( type.GetObjectType()->flags & asOBJ_REF )
  613. {
  614. asSExprContext ctx(engine);
  615. ctx.exprNode = node;
  616. int func = 0;
  617. asSTypeBehaviour *beh = type.GetBehaviour();
  618. if( beh ) func = beh->factory;
  619. if( func > 0 )
  620. {
  621. if( !isGlobalVar )
  622. {
  623. // Call factory and store the handle in the given variable
  624. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  625. // Pop the reference left by the function call
  626. ctx.bc.Instr(asBC_PopPtr);
  627. }
  628. else
  629. {
  630. // Call factory
  631. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  632. // Store the returned handle in the global variable
  633. ctx.bc.Instr(asBC_RDSPtr);
  634. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  635. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  636. ctx.bc.Instr(asBC_PopPtr);
  637. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  638. }
  639. bc->AddCode(&ctx.bc);
  640. return 0;
  641. }
  642. }
  643. else
  644. {
  645. asSTypeBehaviour *beh = type.GetBehaviour();
  646. int func = 0;
  647. if( beh ) func = beh->construct;
  648. // Allocate and initialize with the default constructor
  649. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  650. {
  651. if( !isObjectOnHeap )
  652. {
  653. asASSERT( !isGlobalVar );
  654. // There is nothing to do if there is no function,
  655. // as the memory is already allocated on the stack
  656. if( func )
  657. {
  658. // Call the constructor as a normal function
  659. bc->InstrSHORT(asBC_PSF, (short)offset);
  660. if( deferDest )
  661. bc->Instr(asBC_RDSPtr);
  662. asSExprContext ctx(engine);
  663. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  664. bc->AddCode(&ctx.bc);
  665. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  666. // Mark the object as initialized
  667. bc->ObjInfo(offset, asOBJ_INIT);
  668. }
  669. }
  670. else
  671. {
  672. if( isGlobalVar )
  673. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  674. else
  675. bc->InstrSHORT(asBC_PSF, (short)offset);
  676. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  677. }
  678. return 0;
  679. }
  680. }
  681. // Class has no default factory/constructor.
  682. asCString str;
  683. // TODO: funcdef: asCDataType should have a GetTypeName()
  684. if( type.GetFuncDef() )
  685. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  686. else
  687. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  688. Error(str.AddressOf(), node);
  689. return -1;
  690. }
  691. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  692. {
  693. if( !type.IsReference() )
  694. {
  695. // Call destructor for the data type
  696. if( type.IsObject() )
  697. {
  698. if( isObjectOnHeap || type.IsObjectHandle() )
  699. {
  700. // Free the memory
  701. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  702. }
  703. else
  704. {
  705. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  706. if( type.GetBehaviour()->destruct )
  707. {
  708. // Call the destructor as a regular function
  709. bc->InstrSHORT(asBC_PSF, (short)offset);
  710. asSExprContext ctx(engine);
  711. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  712. bc->AddCode(&ctx.bc);
  713. }
  714. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  715. // Mark the object as destroyed
  716. bc->ObjInfo(offset, asOBJ_UNINIT);
  717. }
  718. }
  719. }
  720. }
  721. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  722. {
  723. int r, c;
  724. script->ConvertPosToRowCol(pos, &r, &c);
  725. bc->Line(r, c);
  726. }
  727. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  728. {
  729. *hasReturn = false;
  730. bool isFinished = false;
  731. bool hasWarned = false;
  732. if( ownVariableScope )
  733. {
  734. bc->Block(true);
  735. AddVariableScope();
  736. }
  737. asCScriptNode *node = block->firstChild;
  738. while( node )
  739. {
  740. if( !hasWarned && (*hasReturn || isFinished) )
  741. {
  742. hasWarned = true;
  743. Warning(TXT_UNREACHABLE_CODE, node);
  744. }
  745. if( node->nodeType == snBreak || node->nodeType == snContinue )
  746. isFinished = true;
  747. asCByteCode statement(engine);
  748. if( node->nodeType == snDeclaration )
  749. CompileDeclaration(node, &statement);
  750. else
  751. CompileStatement(node, hasReturn, &statement);
  752. LineInstr(bc, node->tokenPos);
  753. bc->AddCode(&statement);
  754. if( !hasCompileErrors )
  755. {
  756. asASSERT( tempVariables.GetLength() == 0 );
  757. asASSERT( reservedVariables.GetLength() == 0 );
  758. }
  759. node = node->next;
  760. }
  761. if( ownVariableScope )
  762. {
  763. // Deallocate variables in this block, in reverse order
  764. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  765. {
  766. sVariable *v = variables->variables[n];
  767. // Call variable destructors here, for variables not yet destroyed
  768. // If the block is terminated with a break, continue, or
  769. // return the variables are already destroyed
  770. if( !isFinished && !*hasReturn )
  771. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  772. // Don't deallocate function parameters
  773. if( v->stackOffset > 0 )
  774. DeallocateVariable(v->stackOffset);
  775. }
  776. RemoveVariableScope();
  777. bc->Block(false);
  778. }
  779. }
  780. // Entry
  781. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  782. {
  783. Reset(builder, script, outFunc);
  784. // Add a variable scope (even though variables can't be declared)
  785. AddVariableScope();
  786. asSExprContext ctx(engine);
  787. gvar->isPureConstant = false;
  788. // Parse the initialization nodes
  789. asCParser parser(builder);
  790. if( node )
  791. {
  792. int r = parser.ParseGlobalVarInit(script, node);
  793. if( r < 0 )
  794. return r;
  795. node = parser.GetScriptNode();
  796. }
  797. // Compile the expression
  798. if( node && node->nodeType == snArgList )
  799. {
  800. // Make sure that it is a registered type, and that it isn't a pointer
  801. if( gvar->datatype.GetObjectType() == 0 || gvar->datatype.IsObjectHandle() )
  802. {
  803. Error(TXT_MUST_BE_OBJECT, node);
  804. }
  805. else
  806. {
  807. // Compile the arguments
  808. asCArray<asSExprContext *> args;
  809. if( CompileArgumentList(node, args) >= 0 )
  810. {
  811. // Find all constructors
  812. asCArray<int> funcs;
  813. asSTypeBehaviour *beh = gvar->datatype.GetBehaviour();
  814. if( beh )
  815. {
  816. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  817. funcs = beh->factories;
  818. else
  819. funcs = beh->constructors;
  820. }
  821. asCString str = gvar->datatype.Format();
  822. MatchFunctions(funcs, args, node, str.AddressOf());
  823. if( funcs.GetLength() == 1 )
  824. {
  825. int r = asSUCCESS;
  826. // Add the default values for arguments not explicitly supplied
  827. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  828. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  829. r = CompileDefaultArgs(node, args, func);
  830. if( r == asSUCCESS )
  831. {
  832. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  833. {
  834. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  835. // Store the returned handle in the global variable
  836. ctx.bc.Instr(asBC_RDSPtr);
  837. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  838. ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
  839. ctx.bc.Instr(asBC_PopPtr);
  840. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  841. }
  842. else
  843. {
  844. // Push the address of the location where the variable will be stored on the stack.
  845. // This reference is safe, because the addresses of the global variables cannot change.
  846. // TODO: When serialization of the context is implemented this will probably have to change,
  847. // because this pointer may be on the stack while the context is suspended, and may
  848. // be difficult to serialize as the context doesn't know that the value represents a
  849. // pointer.
  850. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  851. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  852. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  853. PerformFunctionCall(funcs[0], &ctx, true, &args, gvar->datatype.GetObjectType());
  854. }
  855. }
  856. }
  857. }
  858. // Cleanup
  859. for( asUINT n = 0; n < args.GetLength(); n++ )
  860. if( args[n] )
  861. {
  862. asDELETE(args[n],asSExprContext);
  863. }
  864. }
  865. }
  866. else if( node && node->nodeType == snInitList )
  867. {
  868. asCTypeInfo ti;
  869. ti.Set(gvar->datatype);
  870. ti.isVariable = false;
  871. ti.isTemporary = false;
  872. ti.stackOffset = (short)gvar->index;
  873. ti.isLValue = true;
  874. CompileInitList(&ti, node, &ctx.bc);
  875. node = node->next;
  876. }
  877. else if( node )
  878. {
  879. // Compile the right hand expression
  880. asSExprContext expr(engine);
  881. int r = CompileAssignment(node, &expr); if( r < 0 ) return r;
  882. // Assign the value to the variable
  883. if( gvar->datatype.IsPrimitive() )
  884. {
  885. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  886. {
  887. ImplicitConversion(&expr, gvar->datatype, node, asIC_IMPLICIT_CONV);
  888. gvar->isPureConstant = true;
  889. gvar->constantValue = expr.type.qwordValue;
  890. }
  891. asSExprContext lctx(engine);
  892. lctx.type.Set(gvar->datatype);
  893. lctx.type.dataType.MakeReference(true);
  894. lctx.type.dataType.MakeReadOnly(false);
  895. lctx.type.isLValue = true;
  896. // If it is an enum value that is being compiled, then
  897. // we skip this, as the bytecode won't be used anyway
  898. if( !gvar->isEnumValue )
  899. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[gvar->index]->GetAddressOfValue());
  900. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  901. }
  902. else
  903. {
  904. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  905. // just the copy constructor. Only if no appropriate constructor is
  906. // available should the assignment operator be used.
  907. if( !gvar->datatype.IsObjectHandle() )
  908. {
  909. // Call the default constructor to have a valid object for the assignment
  910. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  911. }
  912. asSExprContext lexpr(engine);
  913. lexpr.type.Set(gvar->datatype);
  914. lexpr.type.dataType.MakeReference(true);
  915. lexpr.type.dataType.MakeReadOnly(false);
  916. lexpr.type.stackOffset = -1;
  917. lexpr.type.isLValue = true;
  918. if( gvar->datatype.IsObjectHandle() )
  919. lexpr.type.isExplicitHandle = true;
  920. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  921. // If left expression resolves into a registered type
  922. // check if the assignment operator is overloaded, and check
  923. // the type of the right hand expression. If none is found
  924. // the default action is a direct copy if it is the same type
  925. // and a simple assignment.
  926. bool assigned = false;
  927. // Even though an ASHANDLE can be an explicit handle the assignment needs to be treated by the overloaded operator
  928. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  929. {
  930. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  931. if( assigned )
  932. {
  933. // Pop the resulting value
  934. ctx.bc.Instr(asBC_PopPtr);
  935. // Release the argument
  936. ProcessDeferredParams(&ctx);
  937. }
  938. }
  939. if( !assigned )
  940. {
  941. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  942. // If the expression is constant and the variable also is constant
  943. // then mark the variable as pure constant. This will allow the compiler
  944. // to optimize expressions with this variable.
  945. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  946. {
  947. gvar->isPureConstant = true;
  948. gvar->constantValue = expr.type.qwordValue;
  949. }
  950. // Add expression code to bytecode
  951. MergeExprBytecode(&ctx, &expr);
  952. // Add byte code for storing value of expression in variable
  953. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  954. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node);
  955. // Release temporary variables used by expression
  956. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  957. ctx.bc.Instr(asBC_PopPtr);
  958. }
  959. }
  960. }
  961. else if( gvar->datatype.IsObject() && !gvar->datatype.IsObjectHandle() )
  962. {
  963. // Call the default constructor in case no explicit initialization is given
  964. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  965. }
  966. // Concatenate the bytecode
  967. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  968. // Add information on the line number for the global variable
  969. size_t pos = 0;
  970. if( gvar->idNode )
  971. pos = gvar->idNode->tokenPos;
  972. else if( gvar->nextNode )
  973. pos = gvar->nextNode->tokenPos;
  974. LineInstr(&byteCode, pos);
  975. // Reserve space for all local variables
  976. outFunc->variableSpace = varSize;
  977. byteCode.AddCode(&ctx.bc);
  978. // Deallocate variables in this block, in reverse order
  979. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  980. {
  981. sVariable *v = variables->variables[n];
  982. // Call variable destructors here, for variables not yet destroyed
  983. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  984. DeallocateVariable(v->stackOffset);
  985. }
  986. if( hasCompileErrors ) return -1;
  987. // At this point there should be no variables allocated
  988. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  989. // Remove the variable scope again
  990. RemoveVariableScope();
  991. byteCode.Ret(0);
  992. FinalizeFunction();
  993. #ifdef AS_DEBUG
  994. // DEBUG: output byte code
  995. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  996. #endif
  997. return 0;
  998. }
  999. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1000. {
  1001. asCDataType param = *paramType;
  1002. if( paramType->GetTokenType() == ttQuestion )
  1003. {
  1004. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1005. param = ctx->type.dataType;
  1006. param.MakeHandle(ctx->type.isExplicitHandle);
  1007. param.MakeReference(paramType->IsReference());
  1008. param.MakeReadOnly(paramType->IsReadOnly());
  1009. }
  1010. else
  1011. param = *paramType;
  1012. asCDataType dt = param;
  1013. // Need to protect arguments by reference
  1014. if( isFunction && dt.IsReference() )
  1015. {
  1016. // Allocate a temporary variable of the same type as the argument
  1017. dt.MakeReference(false);
  1018. dt.MakeReadOnly(false);
  1019. int offset;
  1020. if( refType == 1 ) // &in
  1021. {
  1022. ProcessPropertyGetAccessor(ctx, node);
  1023. // Add the type id as hidden arg if the parameter is a ? type
  1024. if( paramType->GetTokenType() == ttQuestion )
  1025. {
  1026. asCByteCode tmpBC(engine);
  1027. // Place the type id on the stack as a hidden parameter
  1028. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1029. // Insert the code before the expression code
  1030. tmpBC.AddCode(&ctx->bc);
  1031. ctx->bc.AddCode(&tmpBC);
  1032. }
  1033. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1034. // Even if the same variable is passed in another argument as non-const then there is no problem
  1035. if( dt.IsPrimitive() || dt.IsNullHandle() )
  1036. {
  1037. IsVariableInitialized(&ctx->type, node);
  1038. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1039. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1040. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1041. ConvertToTempVariable(ctx);
  1042. PushVariableOnStack(ctx, true);
  1043. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1044. }
  1045. else
  1046. {
  1047. IsVariableInitialized(&ctx->type, node);
  1048. if( !isMakingCopy )
  1049. {
  1050. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true);
  1051. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  1052. {
  1053. asCString str;
  1054. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  1055. Error(str.AddressOf(), node);
  1056. ctx->type.Set(param);
  1057. }
  1058. }
  1059. // If the argument already is a temporary
  1060. // variable we don't need to allocate another
  1061. // If the parameter is read-only and the object already is a local
  1062. // variable then it is not necessary to make a copy either
  1063. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
  1064. {
  1065. // Make sure the variable is not used in the expression
  1066. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1067. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  1068. // Allocate and construct the temporary object
  1069. asCByteCode tmpBC(engine);
  1070. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1071. // Insert the code before the expression code
  1072. tmpBC.AddCode(&ctx->bc);
  1073. ctx->bc.AddCode(&tmpBC);
  1074. // Assign the evaluated expression to the temporary variable
  1075. PrepareForAssignment(&dt, ctx, node, true);
  1076. dt.MakeReference(IsVariableOnHeap(offset));
  1077. asCTypeInfo type;
  1078. type.Set(dt);
  1079. type.isTemporary = true;
  1080. type.stackOffset = (short)offset;
  1081. if( dt.IsObjectHandle() )
  1082. type.isExplicitHandle = true;
  1083. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1084. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  1085. ctx->bc.Instr(asBC_PopPtr);
  1086. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  1087. ctx->type = type;
  1088. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1089. if( dt.IsObject() && !dt.IsObjectHandle() )
  1090. ctx->bc.Instr(asBC_RDSPtr);
  1091. if( paramType->IsReadOnly() )
  1092. ctx->type.dataType.MakeReadOnly(true);
  1093. }
  1094. else if( isMakingCopy )
  1095. {
  1096. // We must guarantee that the address to the value is on the stack
  1097. if( ctx->type.dataType.IsObject() &&
  1098. !ctx->type.dataType.IsObjectHandle() &&
  1099. ctx->type.dataType.IsReference() )
  1100. Dereference(ctx, true);
  1101. }
  1102. }
  1103. }
  1104. else if( refType == 2 ) // &out
  1105. {
  1106. // Add the type id as hidden arg if the parameter is a ? type
  1107. if( paramType->GetTokenType() == ttQuestion )
  1108. {
  1109. asCByteCode tmpBC(engine);
  1110. // Place the type id on the stack as a hidden parameter
  1111. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1112. // Insert the code before the expression code
  1113. tmpBC.AddCode(&ctx->bc);
  1114. ctx->bc.AddCode(&tmpBC);
  1115. }
  1116. // Make sure the variable is not used in the expression
  1117. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1118. if( dt.IsPrimitive() )
  1119. {
  1120. ctx->type.SetVariable(dt, offset, true);
  1121. PushVariableOnStack(ctx, true);
  1122. }
  1123. else
  1124. {
  1125. // Allocate and construct the temporary object
  1126. asCByteCode tmpBC(engine);
  1127. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1128. // Insert the code before the expression code
  1129. tmpBC.AddCode(&ctx->bc);
  1130. ctx->bc.AddCode(&tmpBC);
  1131. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  1132. asCTypeInfo type;
  1133. type.Set(dt);
  1134. type.isTemporary = true;
  1135. type.stackOffset = (short)offset;
  1136. ctx->type = type;
  1137. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1138. if( dt.IsObject() && !dt.IsObjectHandle() )
  1139. ctx->bc.Instr(asBC_RDSPtr);
  1140. }
  1141. // After the function returns the temporary variable will
  1142. // be assigned to the expression, if it is a valid lvalue
  1143. }
  1144. else if( refType == asTM_INOUTREF )
  1145. {
  1146. ProcessPropertyGetAccessor(ctx, node);
  1147. // Add the type id as hidden arg if the parameter is a ? type
  1148. if( paramType->GetTokenType() == ttQuestion )
  1149. {
  1150. asCByteCode tmpBC(engine);
  1151. // Place the type id on the stack as a hidden parameter
  1152. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1153. // Insert the code before the expression code
  1154. tmpBC.AddCode(&ctx->bc);
  1155. ctx->bc.AddCode(&tmpBC);
  1156. }
  1157. // Literal constants cannot be passed to inout ref arguments
  1158. if( !ctx->type.isVariable && ctx->type.isConstant )
  1159. {
  1160. Error(TXT_NOT_VALID_REFERENCE, node);
  1161. }
  1162. // Only objects that support object handles
  1163. // can be guaranteed to be safe. Local variables are
  1164. // already safe, so there is no need to add an extra
  1165. // references
  1166. if( !engine->ep.allowUnsafeReferences &&
  1167. !ctx->type.isVariable &&
  1168. ctx->type.dataType.IsObject() &&
  1169. !ctx->type.dataType.IsObjectHandle() &&
  1170. ((ctx->type.dataType.GetBehaviour()->addref &&
  1171. ctx->type.dataType.GetBehaviour()->release) ||
  1172. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1173. {
  1174. // Store a handle to the object as local variable
  1175. asSExprContext tmp(engine);
  1176. asCDataType dt = ctx->type.dataType;
  1177. dt.MakeHandle(true);
  1178. dt.MakeReference(false);
  1179. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1180. // Copy the handle
  1181. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1182. ctx->bc.Instr(asBC_RDSPtr);
  1183. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1184. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1185. ctx->bc.Instr(asBC_PopPtr);
  1186. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1187. dt.MakeHandle(false);
  1188. dt.MakeReference(true);
  1189. // Release previous temporary variable stored in the context (if any)
  1190. if( ctx->type.isTemporary )
  1191. {
  1192. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1193. }
  1194. ctx->type.SetVariable(dt, offset, true);
  1195. }
  1196. // Make sure the reference to the value is on the stack
  1197. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1198. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1199. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !paramType->IsObjectHandle() )
  1200. Dereference(ctx, true);
  1201. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1202. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1203. else if( ctx->type.dataType.IsPrimitive() )
  1204. ctx->bc.Instr(asBC_PshRPtr);
  1205. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1206. {
  1207. asCDataType dt = ctx->type.dataType;
  1208. dt.MakeReference(true);
  1209. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1210. }
  1211. }
  1212. }
  1213. else
  1214. {
  1215. ProcessPropertyGetAccessor(ctx, node);
  1216. if( dt.IsPrimitive() )
  1217. {
  1218. IsVariableInitialized(&ctx->type, node);
  1219. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1220. // Implicitly convert primitives to the parameter type
  1221. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1222. if( ctx->type.isVariable )
  1223. {
  1224. PushVariableOnStack(ctx, dt.IsReference());
  1225. }
  1226. else if( ctx->type.isConstant )
  1227. {
  1228. ConvertToVariable(ctx);
  1229. PushVariableOnStack(ctx, dt.IsReference());
  1230. }
  1231. }
  1232. else
  1233. {
  1234. IsVariableInitialized(&ctx->type, node);
  1235. // Implicitly convert primitives to the parameter type
  1236. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1237. // Was the conversion successful?
  1238. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1239. {
  1240. asCString str;
  1241. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1242. Error(str.AddressOf(), node);
  1243. ctx->type.Set(dt);
  1244. }
  1245. if( dt.IsObjectHandle() )
  1246. ctx->type.isExplicitHandle = true;
  1247. if( dt.IsObject() )
  1248. {
  1249. if( !dt.IsReference() )
  1250. {
  1251. // Objects passed by value must be placed in temporary variables
  1252. // so that they are guaranteed to not be referenced anywhere else.
  1253. // The object must also be allocated on the heap, as the memory will
  1254. // be deleted by in as_callfunc_xxx.
  1255. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1256. PrepareTemporaryObject(node, ctx, true);
  1257. // The implicit conversion shouldn't convert the object to
  1258. // non-reference yet. It will be dereferenced just before the call.
  1259. // Otherwise the object might be missed by the exception handler.
  1260. dt.MakeReference(true);
  1261. }
  1262. else
  1263. {
  1264. // An object passed by reference should place the pointer to
  1265. // the object on the stack.
  1266. dt.MakeReference(false);
  1267. }
  1268. }
  1269. }
  1270. }
  1271. // Don't put any pointer on the stack yet
  1272. if( param.IsReference() || param.IsObject() )
  1273. {
  1274. // &inout parameter may leave the reference on the stack already
  1275. if( refType != 3 )
  1276. {
  1277. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1278. if( ctx->type.isVariable || ctx->type.isTemporary )
  1279. {
  1280. ctx->bc.Instr(asBC_PopPtr);
  1281. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1282. ProcessDeferredParams(ctx);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1288. {
  1289. // When a match has been found, compile the final byte code using correct parameter types
  1290. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1291. // If the function being called is the opAssign or copy constructor for the same type
  1292. // as the argument, then we should avoid making temporary copy of the argument
  1293. bool makingCopy = false;
  1294. if( descr->parameterTypes.GetLength() == 1 &&
  1295. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1296. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1297. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1298. makingCopy = true;
  1299. // Add code for arguments
  1300. asSExprContext e(engine);
  1301. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1302. {
  1303. // Make sure PrepareArgument doesn't use any variable that is already
  1304. // being used by any of the following argument expressions
  1305. int l = int(reservedVariables.GetLength());
  1306. for( int m = n-1; m >= 0; m-- )
  1307. args[m]->bc.GetVarsUsed(reservedVariables);
  1308. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1309. reservedVariables.SetLength(l);
  1310. }
  1311. bc->AddCode(&e.bc);
  1312. }
  1313. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1314. {
  1315. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1316. int offset = 0;
  1317. if( addOneToOffset )
  1318. offset += AS_PTR_SIZE;
  1319. // The address of where the return value should be stored is push on top of the arguments
  1320. if( descr->DoesReturnOnStack() )
  1321. offset += AS_PTR_SIZE;
  1322. #ifdef AS_DEBUG
  1323. // If the function being called is the opAssign or copy constructor for the same type
  1324. // as the argument, then we should avoid making temporary copy of the argument
  1325. bool makingCopy = false;
  1326. if( descr->parameterTypes.GetLength() == 1 &&
  1327. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1328. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1329. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1330. makingCopy = true;
  1331. #endif
  1332. // Move the objects that are sent by value to the stack just before the call
  1333. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1334. {
  1335. if( descr->parameterTypes[n].IsReference() )
  1336. {
  1337. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1338. {
  1339. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1340. {
  1341. #ifdef AS_DEBUG
  1342. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1343. #endif
  1344. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1345. {
  1346. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1347. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1348. // as the value allocated on the stack is guaranteed to be safe
  1349. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1350. else
  1351. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1352. }
  1353. }
  1354. if( args[n]->type.dataType.IsObjectHandle() )
  1355. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1356. }
  1357. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1358. {
  1359. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1360. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1361. {
  1362. // Send the object as a reference to the object,
  1363. // and not to the variable holding the object
  1364. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1365. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1366. // as the value allocated on the stack is guaranteed to be safe
  1367. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1368. else
  1369. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1370. }
  1371. else
  1372. {
  1373. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1374. }
  1375. }
  1376. }
  1377. else if( descr->parameterTypes[n].IsObject() )
  1378. {
  1379. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1380. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1381. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1382. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1383. // The temporary variable must not be freed as it will no longer hold an object
  1384. DeallocateVariable(args[n]->type.stackOffset);
  1385. args[n]->type.isTemporary = false;
  1386. }
  1387. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1388. }
  1389. }
  1390. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1391. {
  1392. asASSERT(node->nodeType == snArgList);
  1393. // Count arguments
  1394. asCScriptNode *arg = node->firstChild;
  1395. int argCount = 0;
  1396. while( arg )
  1397. {
  1398. argCount++;
  1399. arg = arg->next;
  1400. }
  1401. // Prepare the arrays
  1402. args.SetLength(argCount);
  1403. int n;
  1404. for( n = 0; n < argCount; n++ )
  1405. args[n] = 0;
  1406. n = argCount-1;
  1407. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1408. bool anyErrors = false;
  1409. arg = node->lastChild;
  1410. while( arg )
  1411. {
  1412. asSExprContext expr(engine);
  1413. int r = CompileAssignment(arg, &expr);
  1414. if( r < 0 ) anyErrors = true;
  1415. args[n] = asNEW(asSExprContext)(engine);
  1416. if( args[n] == 0 )
  1417. {
  1418. // Out of memory
  1419. return -1;
  1420. }
  1421. MergeExprBytecodeAndType(args[n], &expr);
  1422. n--;
  1423. arg = arg->prev;
  1424. }
  1425. return anyErrors ? -1 : 0;
  1426. }
  1427. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1428. {
  1429. bool anyErrors = false;
  1430. asCArray<int> varsUsed;
  1431. int explicitArgs = (int)args.GetLength();
  1432. for( int p = 0; p < explicitArgs; p++ )
  1433. args[p]->bc.GetVarsUsed(varsUsed);
  1434. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1435. args.SetLength(func->parameterTypes.GetLength());
  1436. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1437. args[c] = 0;
  1438. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1439. {
  1440. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1441. // Parse the default arg string
  1442. asCParser parser(builder);
  1443. asCScriptCode code;
  1444. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1445. int r = parser.ParseExpression(&code);
  1446. if( r < 0 ) { anyErrors = true; continue; }
  1447. asCScriptNode *arg = parser.GetScriptNode();
  1448. // Temporarily set the script code to the default arg expression
  1449. asCScriptCode *origScript = script;
  1450. script = &code;
  1451. // Don't allow the expression to access local variables
  1452. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function
  1453. isCompilingDefaultArg = true;
  1454. asSExprContext expr(engine);
  1455. r = CompileExpression(arg, &expr);
  1456. isCompilingDefaultArg = false;
  1457. script = origScript;
  1458. if( r < 0 )
  1459. {
  1460. asCString msg;
  1461. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1462. Error(msg.AddressOf(), node);
  1463. anyErrors = true;
  1464. continue;
  1465. }
  1466. args[n] = asNEW(asSExprContext)(engine);
  1467. if( args[n] == 0 )
  1468. {
  1469. // Out of memory
  1470. return -1;
  1471. }
  1472. MergeExprBytecodeAndType(args[n], &expr);
  1473. // Make sure the default arg expression doesn't end up
  1474. // with a variable that is used in a previous expression
  1475. if( args[n]->type.isVariable )
  1476. {
  1477. int offset = args[n]->type.stackOffset;
  1478. if( varsUsed.Exists(offset) )
  1479. {
  1480. // Release the current temporary variable
  1481. ReleaseTemporaryVariable(args[n]->type, 0);
  1482. asCDataType dt = args[n]->type.dataType;
  1483. dt.MakeReference(false);
  1484. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1485. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1486. args[n]->bc.ExchangeVar(offset, newOffset);
  1487. args[n]->type.stackOffset = (short)newOffset;
  1488. args[n]->type.isTemporary = true;
  1489. args[n]->type.isVariable = true;
  1490. }
  1491. }
  1492. }
  1493. return anyErrors ? -1 : 0;
  1494. }
  1495. asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1496. {
  1497. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1498. asUINT cost = 0;
  1499. asUINT n;
  1500. if( funcs.GetLength() > 0 )
  1501. {
  1502. // Check the number of parameters in the found functions
  1503. for( n = 0; n < funcs.GetLength(); ++n )
  1504. {
  1505. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1506. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1507. {
  1508. bool noMatch = true;
  1509. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1510. {
  1511. // Count the number of default args
  1512. asUINT defaultArgs = 0;
  1513. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1514. if( desc->defaultArgs[d] )
  1515. defaultArgs++;
  1516. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1517. noMatch = false;
  1518. }
  1519. if( noMatch )
  1520. {
  1521. // remove it from the list
  1522. if( n == funcs.GetLength()-1 )
  1523. funcs.PopLast();
  1524. else
  1525. funcs[n] = funcs.PopLast();
  1526. n--;
  1527. }
  1528. }
  1529. }
  1530. // Match functions with the parameters, and discard those that do not match
  1531. asCArray<int> matchingFuncs = funcs;
  1532. for( n = 0; n < args.GetLength(); ++n )
  1533. {
  1534. asCArray<int> tempFuncs;
  1535. cost += MatchArgument(funcs, tempFuncs, &args[n]->type, n, allowObjectConstruct);
  1536. // Intersect the found functions with the list of matching functions
  1537. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1538. {
  1539. asUINT c;
  1540. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1541. {
  1542. if( matchingFuncs[f] == tempFuncs[c] )
  1543. break;
  1544. }
  1545. // Was the function a match?
  1546. if( c == tempFuncs.GetLength() )
  1547. {
  1548. // No, remove it from the list
  1549. if( f == matchingFuncs.GetLength()-1 )
  1550. matchingFuncs.PopLast();
  1551. else
  1552. matchingFuncs[f] = matchingFuncs.PopLast();
  1553. f--;
  1554. }
  1555. }
  1556. }
  1557. funcs = matchingFuncs;
  1558. }
  1559. if( !isConstMethod )
  1560. FilterConst(funcs);
  1561. if( funcs.GetLength() != 1 && !silent )
  1562. {
  1563. // Build a readable string of the function with parameter types
  1564. asCString str;
  1565. if( scope != "" )
  1566. {
  1567. if( scope == "::" )
  1568. str = scope;
  1569. else
  1570. str = scope + "::";
  1571. }
  1572. str += name;
  1573. str += "(";
  1574. if( args.GetLength() )
  1575. str += args[0]->type.dataType.Format();
  1576. for( n = 1; n < args.GetLength(); n++ )
  1577. str += ", " + args[n]->type.dataType.Format();
  1578. str += ")";
  1579. if( isConstMethod )
  1580. str += " const";
  1581. if( objectType && scope == "" )
  1582. str = objectType->name + "::" + str;
  1583. if( funcs.GetLength() == 0 )
  1584. {
  1585. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1586. Error(str.AddressOf(), node);
  1587. // Print the list of candidates
  1588. if( origFuncs.GetLength() > 0 )
  1589. {
  1590. int r = 0, c = 0;
  1591. asASSERT( node );
  1592. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1593. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1594. PrintMatchingFuncs(origFuncs, node);
  1595. }
  1596. }
  1597. else
  1598. {
  1599. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1600. Error(str.AddressOf(), node);
  1601. PrintMatchingFuncs(funcs, node);
  1602. }
  1603. }
  1604. return cost;
  1605. }
  1606. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1607. {
  1608. // Get the data type
  1609. // TODO: namespace: Use correct implicit namespace from function
  1610. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, "");
  1611. // Declare all variables in this declaration
  1612. asCScriptNode *node = decl->firstChild->next;
  1613. while( node )
  1614. {
  1615. // Is the type allowed?
  1616. if( !type.CanBeInstanciated() )
  1617. {
  1618. asCString str;
  1619. // TODO: Change to "'type' cannot be declared as variable"
  1620. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1621. Error(str.AddressOf(), node);
  1622. // Use int instead to avoid further problems
  1623. type = asCDataType::CreatePrimitive(ttInt, false);
  1624. }
  1625. // A shared object may not declare variables of non-shared types
  1626. if( outFunc->IsShared() )
  1627. {
  1628. asCObjectType *ot = type.GetObjectType();
  1629. if( ot && !ot->IsShared() )
  1630. {
  1631. asCString msg;
  1632. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1633. Error(msg.AddressOf(), decl);
  1634. }
  1635. }
  1636. // Get the name of the identifier
  1637. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1638. // Verify that the name isn't used by a dynamic data type
  1639. if( engine->GetObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  1640. {
  1641. asCString str;
  1642. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1643. Error(str.AddressOf(), node);
  1644. }
  1645. int offset = AllocateVariable(type, false);
  1646. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1647. {
  1648. // TODO: It might be an out-of-memory too
  1649. asCString str;
  1650. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1651. Error(str.AddressOf(), node);
  1652. // Don't continue after this error, as it will just
  1653. // lead to more errors that are likely false
  1654. return;
  1655. }
  1656. // Add marker that the variable has been declared
  1657. bc->VarDecl((int)outFunc->variables.GetLength());
  1658. outFunc->AddVariable(name, type, offset);
  1659. // Keep the node for the variable decl
  1660. asCScriptNode *varNode = node;
  1661. node = node->next;
  1662. if( node && node->nodeType == snArgList )
  1663. {
  1664. // Make sure that it is a registered type, and that is isn't a pointer
  1665. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1666. {
  1667. Error(TXT_MUST_BE_OBJECT, node);
  1668. }
  1669. else
  1670. {
  1671. // Compile the arguments
  1672. asCArray<asSExprContext *> args;
  1673. if( CompileArgumentList(node, args) >= 0 )
  1674. {
  1675. // Find all constructors
  1676. asCArray<int> funcs;
  1677. asSTypeBehaviour *beh = type.GetBehaviour();
  1678. if( beh )
  1679. {
  1680. if( type.GetObjectType()->flags & asOBJ_REF )
  1681. funcs = beh->factories;
  1682. else
  1683. funcs = beh->constructors;
  1684. }
  1685. asCString str = type.Format();
  1686. MatchFunctions(funcs, args, node, str.AddressOf());
  1687. if( funcs.GetLength() == 1 )
  1688. {
  1689. int r = asSUCCESS;
  1690. // Add the default values for arguments not explicitly supplied
  1691. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1692. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1693. r = CompileDefaultArgs(node, args, func);
  1694. if( r == asSUCCESS )
  1695. {
  1696. sVariable *v = variables->GetVariable(name.AddressOf());
  1697. asSExprContext ctx(engine);
  1698. if( v->type.GetObjectType() && (v->type.GetObjectType()->flags & asOBJ_REF) )
  1699. {
  1700. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
  1701. // Pop the reference left by the function call
  1702. ctx.bc.Instr(asBC_PopPtr);
  1703. }
  1704. else
  1705. {
  1706. // When the object is allocated on the heap, the address where the
  1707. // reference will be stored must be pushed on the stack before the
  1708. // arguments. This reference on the stack is safe, even if the script
  1709. // is suspended during the evaluation of the arguments.
  1710. if( v->onHeap )
  1711. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1712. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1713. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1714. // When the object is allocated on the stack, the address to the
  1715. // object is pushed on the stack after the arguments as the object pointer
  1716. if( !v->onHeap )
  1717. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1718. PerformFunctionCall(funcs[0], &ctx, v->onHeap, &args, type.GetObjectType());
  1719. // TODO: value on stack: This probably has to be done in PerformFunctionCall
  1720. // Mark the object as initialized
  1721. ctx.bc.ObjInfo(v->stackOffset, asOBJ_INIT);
  1722. }
  1723. bc->AddCode(&ctx.bc);
  1724. }
  1725. }
  1726. }
  1727. // Cleanup
  1728. for( asUINT n = 0; n < args.GetLength(); n++ )
  1729. if( args[n] )
  1730. {
  1731. asDELETE(args[n],asSExprContext);
  1732. }
  1733. }
  1734. node = node->next;
  1735. }
  1736. else if( node && node->nodeType == snInitList )
  1737. {
  1738. sVariable *v = variables->GetVariable(name.AddressOf());
  1739. asCTypeInfo ti;
  1740. ti.Set(type);
  1741. ti.isVariable = true;
  1742. ti.isTemporary = false;
  1743. ti.stackOffset = (short)v->stackOffset;
  1744. ti.isLValue = true;
  1745. CompileInitList(&ti, node, bc);
  1746. node = node->next;
  1747. }
  1748. else if( node && node->nodeType == snAssignment )
  1749. {
  1750. asSExprContext ctx(engine);
  1751. // TODO: copy: Here we should look for the best matching constructor, instead of
  1752. // just the copy constructor. Only if no appropriate constructor is
  1753. // available should the assignment operator be used.
  1754. // Call the default constructor here
  1755. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, varNode);
  1756. // Compile the expression
  1757. asSExprContext expr(engine);
  1758. int r = CompileAssignment(node, &expr);
  1759. if( r >= 0 )
  1760. {
  1761. if( type.IsPrimitive() )
  1762. {
  1763. if( type.IsReadOnly() && expr.type.isConstant )
  1764. {
  1765. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1766. sVariable *v = variables->GetVariable(name.AddressOf());
  1767. v->isPureConstant = true;
  1768. v->constantValue = expr.type.qwordValue;
  1769. }
  1770. asSExprContext lctx(engine);
  1771. lctx.type.SetVariable(type, offset, false);
  1772. lctx.type.dataType.MakeReadOnly(false);
  1773. lctx.type.isLValue = true;
  1774. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1775. ProcessDeferredParams(&ctx);
  1776. }
  1777. else
  1778. {
  1779. // TODO: runtime optimize: We can use a copy constructor here
  1780. sVariable *v = variables->GetVariable(name.AddressOf());
  1781. asSExprContext lexpr(engine);
  1782. lexpr.type.Set(type);
  1783. lexpr.type.dataType.MakeReference(v->onHeap);
  1784. // Allow initialization of constant variables
  1785. lexpr.type.dataType.MakeReadOnly(false);
  1786. if( type.IsObjectHandle() )
  1787. lexpr.type.isExplicitHandle = true;
  1788. lexpr.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1789. lexpr.type.stackOffset = (short)v->stackOffset;
  1790. lexpr.type.isVariable = true;
  1791. lexpr.type.isLValue = true;
  1792. // If left expression resolves into a registered type
  1793. // check if the assignment operator is overloaded, and check
  1794. // the type of the right hand expression. If none is found
  1795. // the default action is a direct copy if it is the same type
  1796. // and a simple assignment.
  1797. bool assigned = false;
  1798. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  1799. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1800. {
  1801. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1802. if( assigned )
  1803. {
  1804. // Pop the resulting value
  1805. ctx.bc.Instr(asBC_PopPtr);
  1806. // Release the argument
  1807. ProcessDeferredParams(&ctx);
  1808. // Release temporary variable that may be allocated by the overloaded operator
  1809. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1810. }
  1811. }
  1812. if( !assigned )
  1813. {
  1814. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  1815. // If the expression is constant and the variable also is constant
  1816. // then mark the variable as pure constant. This will allow the compiler
  1817. // to optimize expressions with this variable.
  1818. if( v->type.IsReadOnly() && expr.type.isConstant )
  1819. {
  1820. v->isPureConstant = true;
  1821. v->constantValue = expr.type.qwordValue;
  1822. }
  1823. // Add expression code to bytecode
  1824. MergeExprBytecode(&ctx, &expr);
  1825. // Add byte code for storing value of expression in variable
  1826. ctx.bc.AddCode(&lexpr.bc);
  1827. lexpr.type.stackOffset = (short)v->stackOffset;
  1828. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node->prev);
  1829. // Release temporary variables used by expression
  1830. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  1831. ctx.bc.Instr(asBC_PopPtr);
  1832. ProcessDeferredParams(&ctx);
  1833. }
  1834. }
  1835. }
  1836. node = node->next;
  1837. bc->AddCode(&ctx.bc);
  1838. }
  1839. else
  1840. {
  1841. // Call the default constructor here if no explicit initialization is done
  1842. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, varNode);
  1843. }
  1844. }
  1845. }
  1846. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc)
  1847. {
  1848. // Check if the type supports initialization lists
  1849. if( var->dataType.GetObjectType() == 0 ||
  1850. var->dataType.GetBehaviour()->listFactory == 0 ||
  1851. var->dataType.IsObjectHandle() )
  1852. {
  1853. asCString str;
  1854. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  1855. Error(str.AddressOf(), node);
  1856. return;
  1857. }
  1858. // Count the number of elements and initialize the array with the correct size
  1859. int countElements = 0;
  1860. asCScriptNode *el = node->firstChild;
  1861. while( el )
  1862. {
  1863. countElements++;
  1864. el = el->next;
  1865. }
  1866. // Construct the array with the size elements
  1867. // TODO: value on stack: This needs to support value types on the stack as well
  1868. // Find the list factory
  1869. // TODO: initlist: Add support for value types as well
  1870. int funcId = var->dataType.GetBehaviour()->listFactory;
  1871. asCArray<asSExprContext *> args;
  1872. asSExprContext arg1(engine);
  1873. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  1874. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  1875. args.PushLast(&arg1);
  1876. asSExprContext ctx(engine);
  1877. PrepareFunctionCall(funcId, &ctx.bc, args);
  1878. MoveArgsToStack(funcId, &ctx.bc, args, false);
  1879. if( var->isVariable )
  1880. {
  1881. // Call factory and store the handle in the given variable
  1882. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  1883. ctx.bc.Instr(asBC_PopPtr);
  1884. }
  1885. else
  1886. {
  1887. PerformFunctionCall(funcId, &ctx, false, &args);
  1888. // Store the returned handle in the global variable
  1889. ctx.bc.Instr(asBC_RDSPtr);
  1890. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1891. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  1892. ctx.bc.Instr(asBC_PopPtr);
  1893. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1894. }
  1895. bc->AddCode(&ctx.bc);
  1896. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  1897. // initialization lists with different types for different elements? Maybe
  1898. // by using the variable arguments the initialization can be done with one
  1899. // call, passing all the elements as arguments. The registered function can
  1900. // then traverse them however it wants.
  1901. // Find the indexing operator that is not read-only that will be used for all elements
  1902. asCDataType retType;
  1903. retType = var->dataType.GetSubType();
  1904. retType.MakeReference(true);
  1905. retType.MakeReadOnly(false);
  1906. funcId = 0;
  1907. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  1908. {
  1909. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  1910. if( !desc->isReadOnly &&
  1911. desc->parameterTypes.GetLength() == 1 &&
  1912. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1913. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1914. desc->returnType == retType &&
  1915. desc->name == "opIndex" )
  1916. {
  1917. funcId = var->dataType.GetObjectType()->methods[n];
  1918. break;
  1919. }
  1920. }
  1921. if( funcId == 0 )
  1922. {
  1923. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  1924. return;
  1925. }
  1926. asUINT index = 0;
  1927. el = node->firstChild;
  1928. while( el )
  1929. {
  1930. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  1931. {
  1932. asSExprContext lctx(engine);
  1933. asSExprContext rctx(engine);
  1934. if( el->nodeType == snAssignment )
  1935. {
  1936. // Compile the assignment expression
  1937. CompileAssignment(el, &rctx);
  1938. }
  1939. else if( el->nodeType == snInitList )
  1940. {
  1941. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  1942. rctx.type.Set(var->dataType.GetSubType());
  1943. rctx.type.isVariable = true;
  1944. rctx.type.isTemporary = true;
  1945. rctx.type.stackOffset = (short)offset;
  1946. CompileInitList(&rctx.type, el, &rctx.bc);
  1947. // Put the object on the stack
  1948. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  1949. // It is a reference that we place on the stack
  1950. rctx.type.dataType.MakeReference(true);
  1951. }
  1952. // Compile the lvalue
  1953. lctx.bc.InstrDWORD(asBC_PshC4, index);
  1954. if( var->isVariable )
  1955. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  1956. else
  1957. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1958. lctx.bc.Instr(asBC_RDSPtr);
  1959. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  1960. if( !var->dataType.GetSubType().IsPrimitive() )
  1961. lctx.bc.Instr(asBC_PshRPtr);
  1962. lctx.type.Set(var->dataType.GetSubType());
  1963. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  1964. lctx.type.dataType.MakeReference(true);
  1965. // If the element type is handles, then we're expected to do handle assignments
  1966. if( lctx.type.dataType.IsObjectHandle() )
  1967. lctx.type.isExplicitHandle = true;
  1968. lctx.type.isLValue = true;
  1969. asSExprContext ctx(engine);
  1970. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  1971. if( !lctx.type.dataType.IsPrimitive() )
  1972. ctx.bc.Instr(asBC_PopPtr);
  1973. // Release temporary variables used by expression
  1974. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1975. ProcessDeferredParams(&ctx);
  1976. bc->AddCode(&ctx.bc);
  1977. }
  1978. el = el->next;
  1979. index++;
  1980. }
  1981. }
  1982. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  1983. {
  1984. *hasReturn = false;
  1985. if( statement->nodeType == snStatementBlock )
  1986. CompileStatementBlock(statement, true, hasReturn, bc);
  1987. else if( statement->nodeType == snIf )
  1988. CompileIfStatement(statement, hasReturn, bc);
  1989. else if( statement->nodeType == snFor )
  1990. CompileForStatement(statement, bc);
  1991. else if( statement->nodeType == snWhile )
  1992. CompileWhileStatement(statement, bc);
  1993. else if( statement->nodeType == snDoWhile )
  1994. CompileDoWhileStatement(statement, bc);
  1995. else if( statement->nodeType == snExpressionStatement )
  1996. CompileExpressionStatement(statement, bc);
  1997. else if( statement->nodeType == snBreak )
  1998. CompileBreakStatement(statement, bc);
  1999. else if( statement->nodeType == snContinue )
  2000. CompileContinueStatement(statement, bc);
  2001. else if( statement->nodeType == snSwitch )
  2002. CompileSwitchStatement(statement, hasReturn, bc);
  2003. else if( statement->nodeType == snReturn )
  2004. {
  2005. CompileReturnStatement(statement, bc);
  2006. *hasReturn = true;
  2007. }
  2008. }
  2009. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  2010. {
  2011. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  2012. // Reserve label for break statements
  2013. int breakLabel = nextLabel++;
  2014. breakLabels.PushLast(breakLabel);
  2015. // Add a variable scope that will be used by CompileBreak
  2016. // to know where to stop deallocating variables
  2017. AddVariableScope(true, false);
  2018. //---------------------------
  2019. // Compile the switch expression
  2020. //-------------------------------
  2021. // Compile the switch expression
  2022. asSExprContext expr(engine);
  2023. CompileAssignment(snode->firstChild, &expr);
  2024. // Verify that the expression is a primitive type
  2025. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
  2026. {
  2027. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  2028. return;
  2029. }
  2030. ProcessPropertyGetAccessor(&expr, snode);
  2031. // TODO: Need to support 64bit integers
  2032. // Convert the expression to a 32bit variable
  2033. asCDataType to;
  2034. if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
  2035. to.SetTokenType(ttInt);
  2036. else if( expr.type.dataType.IsUnsignedType() )
  2037. to.SetTokenType(ttUInt);
  2038. // Make sure the value is in a variable
  2039. if( expr.type.dataType.IsReference() )
  2040. ConvertToVariable(&expr);
  2041. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  2042. ConvertToVariable(&expr);
  2043. int offset = expr.type.stackOffset;
  2044. ProcessDeferredParams(&expr);
  2045. //-------------------------------
  2046. // Determine case values and labels
  2047. //--------------------------------
  2048. // Remember the first label so that we can later pass the
  2049. // correct label to each CompileCase()
  2050. int firstCaseLabel = nextLabel;
  2051. int defaultLabel = 0;
  2052. asCArray<int> caseValues;
  2053. asCArray<int> caseLabels;
  2054. // Compile all case comparisons and make them jump to the right label
  2055. asCScriptNode *cnode = snode->firstChild->next;
  2056. while( cnode )
  2057. {
  2058. // Each case should have a constant expression
  2059. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2060. {
  2061. // Compile expression
  2062. asSExprContext c(engine);
  2063. CompileExpression(cnode->firstChild, &c);
  2064. // Verify that the result is a constant
  2065. if( !c.type.isConstant )
  2066. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  2067. // Verify that the result is an integral number
  2068. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
  2069. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  2070. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  2071. // Has this case been declared already?
  2072. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  2073. {
  2074. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  2075. }
  2076. // TODO: Optimize: We can insert the numbers sorted already
  2077. // Store constant for later use
  2078. caseValues.PushLast(c.type.intValue);
  2079. // Reserve label for this case
  2080. caseLabels.PushLast(nextLabel++);
  2081. }
  2082. else
  2083. {
  2084. // Is default the last case?
  2085. if( cnode->next )
  2086. {
  2087. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  2088. break;
  2089. }
  2090. // Reserve label for this case
  2091. defaultLabel = nextLabel++;
  2092. }
  2093. cnode = cnode->next;
  2094. }
  2095. // check for empty switch
  2096. if (caseValues.GetLength() == 0)
  2097. {
  2098. Error(TXT_EMPTY_SWITCH, snode);
  2099. return;
  2100. }
  2101. if( defaultLabel == 0 )
  2102. defaultLabel = breakLabel;
  2103. //---------------------------------
  2104. // Output the optimized case comparisons
  2105. // with jumps to the case code
  2106. //------------------------------------
  2107. // Sort the case values by increasing value. Do the sort together with the labels
  2108. // A simple bubble sort is sufficient since we don't expect a huge number of values
  2109. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  2110. {
  2111. for( int bck = fwd - 1; bck >= 0; bck-- )
  2112. {
  2113. int bckp = bck + 1;
  2114. if( caseValues[bck] > caseValues[bckp] )
  2115. {
  2116. // Swap the values in both arrays
  2117. int swap = caseValues[bckp];
  2118. caseValues[bckp] = caseValues[bck];
  2119. caseValues[bck] = swap;
  2120. swap = caseLabels[bckp];
  2121. caseLabels[bckp] = caseLabels[bck];
  2122. caseLabels[bck] = swap;
  2123. }
  2124. else
  2125. break;
  2126. }
  2127. }
  2128. // Find ranges of consecutive numbers
  2129. asCArray<int> ranges;
  2130. ranges.PushLast(0);
  2131. asUINT n;
  2132. for( n = 1; n < caseValues.GetLength(); ++n )
  2133. {
  2134. // We can join numbers that are less than 5 numbers
  2135. // apart since the output code will still be smaller
  2136. if( caseValues[n] > caseValues[n-1] + 5 )
  2137. ranges.PushLast(n);
  2138. }
  2139. // If the value is larger than the largest case value, jump to default
  2140. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2141. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  2142. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2143. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  2144. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2145. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  2146. // binary search instead of a linear search through the ranges
  2147. // For each range
  2148. int range;
  2149. for( range = 0; range < (int)ranges.GetLength(); range++ )
  2150. {
  2151. // Find the largest value in this range
  2152. int maxRange = caseValues[ranges[range]];
  2153. int index = ranges[range];
  2154. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  2155. maxRange = caseValues[index];
  2156. // If there are only 2 numbers then it is better to compare them directly
  2157. if( index - ranges[range] > 2 )
  2158. {
  2159. // If the value is smaller than the smallest case value in the range, jump to default
  2160. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2161. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2162. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2163. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  2164. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2165. int nextRangeLabel = nextLabel++;
  2166. // If this is the last range we don't have to make this test
  2167. if( range < (int)ranges.GetLength() - 1 )
  2168. {
  2169. // If the value is larger than the largest case value in the range, jump to the next range
  2170. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2171. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  2172. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2173. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  2174. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2175. }
  2176. // Jump forward according to the value
  2177. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2178. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2179. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  2180. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2181. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  2182. // Add the list of jumps to the correct labels (any holes, jump to default)
  2183. index = ranges[range];
  2184. for( int n = caseValues[index]; n <= maxRange; n++ )
  2185. {
  2186. if( caseValues[index] == n )
  2187. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  2188. else
  2189. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2190. }
  2191. expr.bc.Label((short)nextRangeLabel);
  2192. }
  2193. else
  2194. {
  2195. // Simply make a comparison with each value
  2196. int n;
  2197. for( n = ranges[range]; n < index; ++n )
  2198. {
  2199. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2200. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  2201. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2202. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2203. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2204. }
  2205. }
  2206. }
  2207. // Catch any value that falls trough
  2208. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2209. // Release the temporary variable previously stored
  2210. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2211. //----------------------------------
  2212. // Output case implementations
  2213. //----------------------------------
  2214. // Compile case implementations, each one with the label before it
  2215. cnode = snode->firstChild->next;
  2216. while( cnode )
  2217. {
  2218. // Each case should have a constant expression
  2219. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2220. {
  2221. expr.bc.Label((short)firstCaseLabel++);
  2222. CompileCase(cnode->firstChild->next, &expr.bc);
  2223. }
  2224. else
  2225. {
  2226. expr.bc.Label((short)defaultLabel);
  2227. // Is default the last case?
  2228. if( cnode->next )
  2229. {
  2230. // We've already reported this error
  2231. break;
  2232. }
  2233. CompileCase(cnode->firstChild, &expr.bc);
  2234. }
  2235. cnode = cnode->next;
  2236. }
  2237. //--------------------------------
  2238. bc->AddCode(&expr.bc);
  2239. // Add break label
  2240. bc->Label((short)breakLabel);
  2241. breakLabels.PopLast();
  2242. RemoveVariableScope();
  2243. }
  2244. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2245. {
  2246. bool isFinished = false;
  2247. bool hasReturn = false;
  2248. while( node )
  2249. {
  2250. if( hasReturn || isFinished )
  2251. {
  2252. Warning(TXT_UNREACHABLE_CODE, node);
  2253. break;
  2254. }
  2255. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2256. isFinished = true;
  2257. asCByteCode statement(engine);
  2258. if( node->nodeType == snDeclaration )
  2259. {
  2260. Error(TXT_DECL_IN_SWITCH, node);
  2261. // Compile it anyway to avoid further compiler errors
  2262. CompileDeclaration(node, &statement);
  2263. }
  2264. else
  2265. CompileStatement(node, &hasReturn, &statement);
  2266. LineInstr(bc, node->tokenPos);
  2267. bc->AddCode(&statement);
  2268. if( !hasCompileErrors )
  2269. asASSERT( tempVariables.GetLength() == 0 );
  2270. node = node->next;
  2271. }
  2272. }
  2273. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2274. {
  2275. // We will use one label for the if statement
  2276. // and possibly another for the else statement
  2277. int afterLabel = nextLabel++;
  2278. // Compile the expression
  2279. asSExprContext expr(engine);
  2280. CompileAssignment(inode->firstChild, &expr);
  2281. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2282. {
  2283. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2284. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2285. }
  2286. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2287. ProcessDeferredParams(&expr);
  2288. if( !expr.type.isConstant )
  2289. {
  2290. ProcessPropertyGetAccessor(&expr, inode);
  2291. ConvertToVariable(&expr);
  2292. // Add byte code from the expression
  2293. bc->AddCode(&expr.bc);
  2294. // Add a test
  2295. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2296. bc->Instr(asBC_ClrHi);
  2297. bc->InstrDWORD(asBC_JZ, afterLabel);
  2298. ReleaseTemporaryVariable(expr.type, bc);
  2299. }
  2300. else if( expr.type.dwordValue == 0 )
  2301. {
  2302. // Jump to the else case
  2303. bc->InstrINT(asBC_JMP, afterLabel);
  2304. // TODO: Should we warn that the expression will always go to the else?
  2305. }
  2306. // Compile the if statement
  2307. bool origIsConstructorCalled = m_isConstructorCalled;
  2308. bool hasReturn1;
  2309. asCByteCode ifBC(engine);
  2310. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2311. // Add the byte code
  2312. LineInstr(bc, inode->firstChild->next->tokenPos);
  2313. bc->AddCode(&ifBC);
  2314. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2315. {
  2316. // Don't allow if( expr );
  2317. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2318. }
  2319. // If one of the statements call the constructor, the other must as well
  2320. // otherwise it is possible the constructor is never called
  2321. bool constructorCall1 = false;
  2322. bool constructorCall2 = false;
  2323. if( !origIsConstructorCalled && m_isConstructorCalled )
  2324. constructorCall1 = true;
  2325. // Do we have an else statement?
  2326. if( inode->firstChild->next != inode->lastChild )
  2327. {
  2328. // Reset the constructor called flag so the else statement can call the constructor too
  2329. m_isConstructorCalled = origIsConstructorCalled;
  2330. int afterElse = 0;
  2331. if( !hasReturn1 )
  2332. {
  2333. afterElse = nextLabel++;
  2334. // Add jump to after the else statement
  2335. bc->InstrINT(asBC_JMP, afterElse);
  2336. }
  2337. // Add label for the else statement
  2338. bc->Label((short)afterLabel);
  2339. bool hasReturn2;
  2340. asCByteCode elseBC(engine);
  2341. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2342. // Add byte code for the else statement
  2343. LineInstr(bc, inode->lastChild->tokenPos);
  2344. bc->AddCode(&elseBC);
  2345. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2346. {
  2347. // Don't allow if( expr ) {} else;
  2348. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2349. }
  2350. if( !hasReturn1 )
  2351. {
  2352. // Add label for the end of else statement
  2353. bc->Label((short)afterElse);
  2354. }
  2355. // The if statement only has return if both alternatives have
  2356. *hasReturn = hasReturn1 && hasReturn2;
  2357. if( !origIsConstructorCalled && m_isConstructorCalled )
  2358. constructorCall2 = true;
  2359. }
  2360. else
  2361. {
  2362. // Add label for the end of if statement
  2363. bc->Label((short)afterLabel);
  2364. *hasReturn = false;
  2365. }
  2366. // Make sure both or neither conditions call a constructor
  2367. if( (constructorCall1 && !constructorCall2) ||
  2368. (constructorCall2 && !constructorCall1) )
  2369. {
  2370. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2371. }
  2372. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2373. }
  2374. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2375. {
  2376. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2377. AddVariableScope(true, true);
  2378. // We will use three labels for the for loop
  2379. int conditionLabel = nextLabel++;
  2380. int afterLabel = nextLabel++;
  2381. int continueLabel = nextLabel++;
  2382. int insideLabel = nextLabel++;
  2383. continueLabels.PushLast(continueLabel);
  2384. breakLabels.PushLast(afterLabel);
  2385. //---------------------------------------
  2386. // Compile the initialization statement
  2387. asCByteCode initBC(engine);
  2388. if( fnode->firstChild->nodeType == snDeclaration )
  2389. CompileDeclaration(fnode->firstChild, &initBC);
  2390. else
  2391. CompileExpressionStatement(fnode->firstChild, &initBC);
  2392. //-----------------------------------
  2393. // Compile the condition statement
  2394. asSExprContext expr(engine);
  2395. asCScriptNode *second = fnode->firstChild->next;
  2396. if( second->firstChild )
  2397. {
  2398. int r = CompileAssignment(second->firstChild, &expr);
  2399. if( r >= 0 )
  2400. {
  2401. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2402. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2403. else
  2404. {
  2405. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2406. ProcessDeferredParams(&expr);
  2407. ProcessPropertyGetAccessor(&expr, second);
  2408. // If expression is false exit the loop
  2409. ConvertToVariable(&expr);
  2410. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2411. expr.bc.Instr(asBC_ClrHi);
  2412. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  2413. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2414. }
  2415. }
  2416. }
  2417. //---------------------------
  2418. // Compile the increment statement
  2419. asCByteCode nextBC(engine);
  2420. asCScriptNode *third = second->next;
  2421. if( third->nodeType == snExpressionStatement )
  2422. CompileExpressionStatement(third, &nextBC);
  2423. //------------------------------
  2424. // Compile loop statement
  2425. bool hasReturn;
  2426. asCByteCode forBC(engine);
  2427. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2428. //-------------------------------
  2429. // Join the code pieces
  2430. bc->AddCode(&initBC);
  2431. bc->InstrDWORD(asBC_JMP, conditionLabel);
  2432. bc->Label((short)insideLabel);
  2433. // Add a suspend bytecode inside the loop to guarantee
  2434. // that the application can suspend the execution
  2435. bc->Instr(asBC_SUSPEND);
  2436. bc->InstrPTR(asBC_JitEntry, 0);
  2437. LineInstr(bc, fnode->lastChild->tokenPos);
  2438. bc->AddCode(&forBC);
  2439. bc->Label((short)continueLabel);
  2440. bc->AddCode(&nextBC);
  2441. bc->Label((short)conditionLabel);
  2442. if( expr.bc.GetLastInstr() == -1 )
  2443. // There is no condition, so we just always jump
  2444. bc->InstrDWORD(asBC_JMP, insideLabel);
  2445. else
  2446. bc->AddCode(&expr.bc);
  2447. bc->Label((short)afterLabel);
  2448. continueLabels.PopLast();
  2449. breakLabels.PopLast();
  2450. // Deallocate variables in this block, in reverse order
  2451. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2452. {
  2453. sVariable *v = variables->variables[n];
  2454. // Call variable destructors here, for variables not yet destroyed
  2455. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2456. // Don't deallocate function parameters
  2457. if( v->stackOffset > 0 )
  2458. DeallocateVariable(v->stackOffset);
  2459. }
  2460. RemoveVariableScope();
  2461. }
  2462. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2463. {
  2464. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2465. AddVariableScope(true, true);
  2466. // We will use two labels for the while loop
  2467. int beforeLabel = nextLabel++;
  2468. int afterLabel = nextLabel++;
  2469. continueLabels.PushLast(beforeLabel);
  2470. breakLabels.PushLast(afterLabel);
  2471. // Add label before the expression
  2472. bc->Label((short)beforeLabel);
  2473. // Compile expression
  2474. asSExprContext expr(engine);
  2475. CompileAssignment(wnode->firstChild, &expr);
  2476. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2477. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2478. else
  2479. {
  2480. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2481. ProcessDeferredParams(&expr);
  2482. ProcessPropertyGetAccessor(&expr, wnode);
  2483. // Add byte code for the expression
  2484. ConvertToVariable(&expr);
  2485. bc->AddCode(&expr.bc);
  2486. // Jump to end of statement if expression is false
  2487. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2488. bc->Instr(asBC_ClrHi);
  2489. bc->InstrDWORD(asBC_JZ, afterLabel);
  2490. ReleaseTemporaryVariable(expr.type, bc);
  2491. }
  2492. // Add a suspend bytecode inside the loop to guarantee
  2493. // that the application can suspend the execution
  2494. bc->Instr(asBC_SUSPEND);
  2495. bc->InstrPTR(asBC_JitEntry, 0);
  2496. // Compile statement
  2497. bool hasReturn;
  2498. asCByteCode whileBC(engine);
  2499. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2500. // Add byte code for the statement
  2501. LineInstr(bc, wnode->lastChild->tokenPos);
  2502. bc->AddCode(&whileBC);
  2503. // Jump to the expression
  2504. bc->InstrINT(asBC_JMP, beforeLabel);
  2505. // Add label after the statement
  2506. bc->Label((short)afterLabel);
  2507. continueLabels.PopLast();
  2508. breakLabels.PopLast();
  2509. RemoveVariableScope();
  2510. }
  2511. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2512. {
  2513. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2514. AddVariableScope(true, true);
  2515. // We will use two labels for the while loop
  2516. int beforeLabel = nextLabel++;
  2517. int beforeTest = nextLabel++;
  2518. int afterLabel = nextLabel++;
  2519. continueLabels.PushLast(beforeTest);
  2520. breakLabels.PushLast(afterLabel);
  2521. // Add label before the statement
  2522. bc->Label((short)beforeLabel);
  2523. // Compile statement
  2524. bool hasReturn;
  2525. asCByteCode whileBC(engine);
  2526. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2527. // Add byte code for the statement
  2528. LineInstr(bc, wnode->firstChild->tokenPos);
  2529. bc->AddCode(&whileBC);
  2530. // Add label before the expression
  2531. bc->Label((short)beforeTest);
  2532. // Add a suspend bytecode inside the loop to guarantee
  2533. // that the application can suspend the execution
  2534. bc->Instr(asBC_SUSPEND);
  2535. bc->InstrPTR(asBC_JitEntry, 0);
  2536. // Add a line instruction
  2537. LineInstr(bc, wnode->lastChild->tokenPos);
  2538. // Compile expression
  2539. asSExprContext expr(engine);
  2540. CompileAssignment(wnode->lastChild, &expr);
  2541. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2542. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2543. else
  2544. {
  2545. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2546. ProcessDeferredParams(&expr);
  2547. ProcessPropertyGetAccessor(&expr, wnode);
  2548. // Add byte code for the expression
  2549. ConvertToVariable(&expr);
  2550. bc->AddCode(&expr.bc);
  2551. // Jump to next iteration if expression is true
  2552. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2553. bc->Instr(asBC_ClrHi);
  2554. bc->InstrDWORD(asBC_JNZ, beforeLabel);
  2555. ReleaseTemporaryVariable(expr.type, bc);
  2556. }
  2557. // Add label after the statement
  2558. bc->Label((short)afterLabel);
  2559. continueLabels.PopLast();
  2560. breakLabels.PopLast();
  2561. RemoveVariableScope();
  2562. }
  2563. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2564. {
  2565. if( breakLabels.GetLength() == 0 )
  2566. {
  2567. Error(TXT_INVALID_BREAK, node);
  2568. return;
  2569. }
  2570. // Add destructor calls for all variables that will go out of scope
  2571. // Put this clean up in a block to allow exception handler to understand them
  2572. bc->Block(true);
  2573. asCVariableScope *vs = variables;
  2574. while( !vs->isBreakScope )
  2575. {
  2576. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2577. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2578. vs = vs->parent;
  2579. }
  2580. bc->Block(false);
  2581. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2582. }
  2583. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2584. {
  2585. if( continueLabels.GetLength() == 0 )
  2586. {
  2587. Error(TXT_INVALID_CONTINUE, node);
  2588. return;
  2589. }
  2590. // Add destructor calls for all variables that will go out of scope
  2591. // Put this clean up in a block to allow exception handler to understand them
  2592. bc->Block(true);
  2593. asCVariableScope *vs = variables;
  2594. while( !vs->isContinueScope )
  2595. {
  2596. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2597. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2598. vs = vs->parent;
  2599. }
  2600. bc->Block(false);
  2601. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2602. }
  2603. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2604. {
  2605. if( enode->firstChild )
  2606. {
  2607. // Compile the expression
  2608. asSExprContext expr(engine);
  2609. CompileAssignment(enode->firstChild, &expr);
  2610. // If we get here and there is still an unprocessed property
  2611. // accessor, then process it as a get access. Don't call if there is
  2612. // already a compile error, or we might report an error that is not valid
  2613. if( !hasCompileErrors )
  2614. ProcessPropertyGetAccessor(&expr, enode);
  2615. // Pop the value from the stack
  2616. if( !expr.type.dataType.IsPrimitive() )
  2617. expr.bc.Instr(asBC_PopPtr);
  2618. // Release temporary variables used by expression
  2619. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2620. ProcessDeferredParams(&expr);
  2621. bc->AddCode(&expr.bc);
  2622. }
  2623. }
  2624. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  2625. {
  2626. // If the object already is stored in temporary variable then nothing needs to be done
  2627. // Note, a type can be temporary without being a variable, in which case it is holding off
  2628. // on releasing a previously used object.
  2629. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2630. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2631. {
  2632. // If the temporary object is currently not a reference
  2633. // the expression needs to be reevaluated to a reference
  2634. if( !ctx->type.dataType.IsReference() )
  2635. {
  2636. ctx->bc.Instr(asBC_PopPtr);
  2637. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2638. ctx->type.dataType.MakeReference(true);
  2639. }
  2640. return;
  2641. }
  2642. // Allocate temporary variable
  2643. asCDataType dt = ctx->type.dataType;
  2644. dt.MakeReference(false);
  2645. dt.MakeReadOnly(false);
  2646. int offset = AllocateVariable(dt, true, forceOnHeap);
  2647. // Objects stored on the stack are not considered references
  2648. dt.MakeReference(IsVariableOnHeap(offset));
  2649. asCTypeInfo lvalue;
  2650. lvalue.Set(dt);
  2651. lvalue.isTemporary = true;
  2652. lvalue.stackOffset = (short)offset;
  2653. lvalue.isVariable = true;
  2654. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2655. if( !dt.IsObjectHandle() &&
  2656. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2657. {
  2658. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2659. // Use the copy constructor/factory when available
  2660. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2661. }
  2662. else
  2663. {
  2664. // Allocate and construct the temporary object
  2665. int r = CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2666. if( r < 0 )
  2667. {
  2668. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2669. }
  2670. else
  2671. {
  2672. // Assign the object to the temporary variable
  2673. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2674. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2675. r = PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2676. if( r < 0 )
  2677. {
  2678. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2679. }
  2680. // Pop the original reference
  2681. ctx->bc.Instr(asBC_PopPtr);
  2682. }
  2683. }
  2684. // If the expression was holding off on releasing a
  2685. // previously used object, we need to release it now
  2686. if( ctx->type.isTemporary )
  2687. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2688. // Push the reference to the temporary variable on the stack
  2689. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2690. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2691. ctx->type = lvalue;
  2692. }
  2693. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2694. {
  2695. // Get return type and location
  2696. sVariable *v = variables->GetVariable("return");
  2697. // Basic validations
  2698. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2699. {
  2700. Error(TXT_MUST_RETURN_VALUE, rnode);
  2701. return;
  2702. }
  2703. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2704. {
  2705. Error(TXT_CANT_RETURN_VALUE, rnode);
  2706. return;
  2707. }
  2708. // Compile the expression
  2709. if( rnode->firstChild )
  2710. {
  2711. // Compile the expression
  2712. asSExprContext expr(engine);
  2713. int r = CompileAssignment(rnode->firstChild, &expr);
  2714. if( r < 0 ) return;
  2715. if( v->type.IsReference() )
  2716. {
  2717. // The expression that gives the reference must not use any of the
  2718. // variables that must be destroyed upon exit, because then it means
  2719. // reference will stay alive while the clean-up is done, which could
  2720. // potentially mean that the reference is invalidated by the clean-up.
  2721. //
  2722. // When the function is returning a reference, the clean-up of the
  2723. // variables must be done before the evaluation of the expression.
  2724. //
  2725. // A reference to a global variable, or a class member for class methods
  2726. // should be allowed to be returned.
  2727. if( !(expr.type.dataType.IsReference() ||
  2728. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2729. {
  2730. // Clean up the potential deferred parameters
  2731. ProcessDeferredParams(&expr);
  2732. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2733. return;
  2734. }
  2735. // No references to local variables, temporary variables, or parameters
  2736. // are allowed to be returned, since they go out of scope when the function
  2737. // returns. Even reference parameters are disallowed, since it is not possible
  2738. // to know the scope of them. The exception is the 'this' pointer, which
  2739. // is treated by the compiler as a local variable, but isn't really so.
  2740. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2741. {
  2742. // Clean up the potential deferred parameters
  2743. ProcessDeferredParams(&expr);
  2744. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2745. return;
  2746. }
  2747. // The type must match exactly as we cannot convert
  2748. // the reference without loosing the original value
  2749. if( !(v->type == expr.type.dataType ||
  2750. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRef(expr.type.dataType))) )
  2751. {
  2752. // Clean up the potential deferred parameters
  2753. ProcessDeferredParams(&expr);
  2754. asCString str;
  2755. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2756. Error(str.AddressOf(), rnode);
  2757. return;
  2758. }
  2759. // The expression must not have any deferred expressions, because the evaluation
  2760. // of these cannot be done without keeping the reference which is not safe
  2761. if( expr.deferredParams.GetLength() )
  2762. {
  2763. // Clean up the potential deferred parameters
  2764. ProcessDeferredParams(&expr);
  2765. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2766. return;
  2767. }
  2768. // Make sure the expression isn't using any local variables that
  2769. // will need to be cleaned up before the function completes
  2770. asCArray<int> usedVars;
  2771. expr.bc.GetVarsUsed(usedVars);
  2772. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  2773. {
  2774. int var = GetVariableSlot(usedVars[n]);
  2775. if( var != -1 )
  2776. {
  2777. asCDataType dt = variableAllocations[var];
  2778. if( dt.IsObject() )
  2779. {
  2780. ProcessDeferredParams(&expr);
  2781. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  2782. return;
  2783. }
  2784. }
  2785. }
  2786. // All objects in the function must be cleaned up before the expression
  2787. // is evaluated, otherwise there is a possibility that the cleanup will
  2788. // invalidate the reference.
  2789. // Destroy the local variables before loading
  2790. // the reference into the register. This will
  2791. // be done before the expression is evaluated.
  2792. DestroyVariables(bc);
  2793. // For primitives the reference is already in the register,
  2794. // but for non-primitives the reference is on the stack so we
  2795. // need to load it into the register
  2796. if( !expr.type.dataType.IsPrimitive() )
  2797. {
  2798. if( !expr.type.dataType.IsObjectHandle() &&
  2799. expr.type.dataType.IsReference() )
  2800. expr.bc.Instr(asBC_RDSPtr);
  2801. expr.bc.Instr(asBC_PopRPtr);
  2802. }
  2803. // There are no temporaries to release so we're done
  2804. }
  2805. else // if( !v->type.IsReference() )
  2806. {
  2807. ProcessPropertyGetAccessor(&expr, rnode);
  2808. // Prepare the value for assignment
  2809. IsVariableInitialized(&expr.type, rnode->firstChild);
  2810. if( v->type.IsPrimitive() )
  2811. {
  2812. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2813. // Implicitly convert the value to the return type
  2814. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2815. // Verify that the conversion was successful
  2816. if( expr.type.dataType != v->type )
  2817. {
  2818. asCString str;
  2819. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2820. Error(str.AddressOf(), rnode);
  2821. return;
  2822. }
  2823. else
  2824. {
  2825. ConvertToVariable(&expr);
  2826. // Clean up the local variables and process deferred parameters
  2827. DestroyVariables(&expr.bc);
  2828. ProcessDeferredParams(&expr);
  2829. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2830. // Load the variable in the register
  2831. if( v->type.GetSizeOnStackDWords() == 1 )
  2832. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2833. else
  2834. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  2835. }
  2836. }
  2837. else if( v->type.IsObject() )
  2838. {
  2839. // Value types are returned on the stack, in a location
  2840. // that has been reserved by the calling function.
  2841. if( outFunc->DoesReturnOnStack() )
  2842. {
  2843. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  2844. // it should be called directly instead of first converting the expression and
  2845. // then copy the value.
  2846. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2847. {
  2848. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2849. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2850. {
  2851. asCString str;
  2852. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2853. Error(str.AddressOf(), rnode->firstChild);
  2854. return;
  2855. }
  2856. }
  2857. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  2858. if( v->type.GetObjectType()->beh.copyconstruct )
  2859. {
  2860. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  2861. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  2862. }
  2863. else
  2864. {
  2865. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  2866. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, false, true);
  2867. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  2868. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2869. expr.bc.Instr(asBC_RDSPtr);
  2870. asSExprContext lexpr(engine);
  2871. lexpr.type.Set(v->type);
  2872. lexpr.type.isLValue = true;
  2873. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  2874. expr.bc.Instr(asBC_PopPtr);
  2875. // Release any temporary variable
  2876. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2877. }
  2878. // Clean up the local variables and process deferred parameters
  2879. DestroyVariables(&expr.bc);
  2880. ProcessDeferredParams(&expr);
  2881. }
  2882. else
  2883. {
  2884. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  2885. // Prepare the expression to be loaded into the object
  2886. // register. This will place the reference in local variable
  2887. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  2888. // Pop the reference to the temporary variable
  2889. expr.bc.Instr(asBC_PopPtr);
  2890. // Clean up the local variables and process deferred parameters
  2891. DestroyVariables(&expr.bc);
  2892. ProcessDeferredParams(&expr);
  2893. // Load the object pointer into the object register
  2894. // LOADOBJ also clears the address in the variable
  2895. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  2896. // LOADOBJ cleared the address in the variable so the object will not be freed
  2897. // here, but the temporary variable must still be freed so the slot can be reused
  2898. // By releasing without the bytecode we do just that.
  2899. ReleaseTemporaryVariable(expr.type, 0);
  2900. }
  2901. }
  2902. }
  2903. bc->AddCode(&expr.bc);
  2904. }
  2905. else
  2906. {
  2907. // For functions that don't return anything
  2908. // we just detroy the local variables
  2909. DestroyVariables(bc);
  2910. }
  2911. // Jump to the end of the function
  2912. bc->InstrINT(asBC_JMP, 0);
  2913. }
  2914. void asCCompiler::DestroyVariables(asCByteCode *bc)
  2915. {
  2916. // Call destructor on all variables except for the function parameters
  2917. // Put the clean-up in a block to allow exception handler to understand this
  2918. bc->Block(true);
  2919. asCVariableScope *vs = variables;
  2920. while( vs )
  2921. {
  2922. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2923. if( vs->variables[n]->stackOffset > 0 )
  2924. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2925. vs = vs->parent;
  2926. }
  2927. bc->Block(false);
  2928. }
  2929. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  2930. {
  2931. variables = asNEW(asCVariableScope)(variables);
  2932. if( variables == 0 )
  2933. {
  2934. // Out of memory
  2935. return;
  2936. }
  2937. variables->isBreakScope = isBreakScope;
  2938. variables->isContinueScope = isContinueScope;
  2939. }
  2940. void asCCompiler::RemoveVariableScope()
  2941. {
  2942. if( variables )
  2943. {
  2944. asCVariableScope *var = variables;
  2945. variables = variables->parent;
  2946. asDELETE(var,asCVariableScope);
  2947. }
  2948. }
  2949. void asCCompiler::Error(const char *msg, asCScriptNode *node)
  2950. {
  2951. asCString str;
  2952. int r = 0, c = 0;
  2953. asASSERT( node );
  2954. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2955. builder->WriteError(script->name.AddressOf(), msg, r, c);
  2956. hasCompileErrors = true;
  2957. }
  2958. void asCCompiler::Warning(const char *msg, asCScriptNode *node)
  2959. {
  2960. asCString str;
  2961. int r = 0, c = 0;
  2962. asASSERT( node );
  2963. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2964. builder->WriteWarning(script->name.AddressOf(), msg, r, c);
  2965. }
  2966. void asCCompiler::Information(const char *msg, asCScriptNode *node)
  2967. {
  2968. asCString str;
  2969. int r = 0, c = 0;
  2970. asASSERT( node );
  2971. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2972. builder->WriteInfo(script->name.AddressOf(), msg, r, c, false);
  2973. }
  2974. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  2975. {
  2976. int r = 0, c = 0;
  2977. asASSERT( node );
  2978. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2979. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  2980. {
  2981. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  2982. builder->WriteInfo(script->name.AddressOf(), func->GetDeclaration(true), r, c, false);
  2983. }
  2984. }
  2985. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  2986. {
  2987. int l = int(reservedVariables.GetLength());
  2988. ctx->bc.GetVarsUsed(reservedVariables);
  2989. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  2990. reservedVariables.SetLength(l);
  2991. return var;
  2992. }
  2993. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  2994. {
  2995. asCDataType t(type);
  2996. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  2997. t.SetTokenType(ttInt);
  2998. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  2999. t.SetTokenType(ttDouble);
  3000. // Only null handles have the token type unrecognized token
  3001. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  3002. bool isOnHeap = true;
  3003. if( t.IsPrimitive() ||
  3004. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  3005. {
  3006. // Primitives and value types (unless overridden) are allocated on the stack
  3007. isOnHeap = false;
  3008. }
  3009. // Find a free location with the same type
  3010. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  3011. {
  3012. int slot = freeVariables[n];
  3013. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  3014. variableIsTemporary[slot] == isTemporary &&
  3015. variableIsOnHeap[slot] == isOnHeap )
  3016. {
  3017. // We can't return by slot, must count variable sizes
  3018. int offset = GetVariableOffset(slot);
  3019. // Verify that it is not in the list of reserved variables
  3020. bool isUsed = false;
  3021. if( reservedVariables.GetLength() )
  3022. isUsed = reservedVariables.Exists(offset);
  3023. if( !isUsed )
  3024. {
  3025. if( n != freeVariables.GetLength() - 1 )
  3026. freeVariables[n] = freeVariables.PopLast();
  3027. else
  3028. freeVariables.PopLast();
  3029. if( isTemporary )
  3030. tempVariables.PushLast(offset);
  3031. return offset;
  3032. }
  3033. }
  3034. }
  3035. variableAllocations.PushLast(t);
  3036. variableIsTemporary.PushLast(isTemporary);
  3037. variableIsOnHeap.PushLast(isOnHeap);
  3038. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  3039. if( isTemporary )
  3040. tempVariables.PushLast(offset);
  3041. return offset;
  3042. }
  3043. int asCCompiler::GetVariableOffset(int varIndex)
  3044. {
  3045. // Return offset to the last dword on the stack
  3046. int varOffset = 1;
  3047. for( int n = 0; n < varIndex; n++ )
  3048. {
  3049. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3050. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  3051. else
  3052. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  3053. }
  3054. if( varIndex < (int)variableAllocations.GetLength() )
  3055. {
  3056. int size;
  3057. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  3058. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  3059. else
  3060. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  3061. if( size > 1 )
  3062. varOffset += size-1;
  3063. }
  3064. return varOffset;
  3065. }
  3066. int asCCompiler::GetVariableSlot(int offset)
  3067. {
  3068. int varOffset = 1;
  3069. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  3070. {
  3071. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3072. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  3073. else
  3074. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  3075. if( varOffset == offset )
  3076. return n;
  3077. varOffset++;
  3078. }
  3079. return -1;
  3080. }
  3081. bool asCCompiler::IsVariableOnHeap(int offset)
  3082. {
  3083. int varSlot = GetVariableSlot(offset);
  3084. if( varSlot < 0 )
  3085. {
  3086. // This happens for function arguments that are considered as on the heap
  3087. return true;
  3088. }
  3089. return variableIsOnHeap[varSlot];
  3090. }
  3091. void asCCompiler::DeallocateVariable(int offset)
  3092. {
  3093. // Remove temporary variable
  3094. int n;
  3095. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  3096. {
  3097. if( offset == tempVariables[n] )
  3098. {
  3099. if( n == (int)tempVariables.GetLength()-1 )
  3100. tempVariables.PopLast();
  3101. else
  3102. tempVariables[n] = tempVariables.PopLast();
  3103. break;
  3104. }
  3105. }
  3106. n = GetVariableSlot(offset);
  3107. if( n != -1 )
  3108. {
  3109. freeVariables.PushLast(n);
  3110. return;
  3111. }
  3112. // We might get here if the variable was implicitly declared
  3113. // because it was use before a formal declaration, in this case
  3114. // the offset is 0x7FFF
  3115. asASSERT(offset == 0x7FFF);
  3116. }
  3117. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  3118. {
  3119. if( t.isTemporary )
  3120. {
  3121. ReleaseTemporaryVariable(t.stackOffset, bc);
  3122. t.isTemporary = false;
  3123. }
  3124. }
  3125. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  3126. {
  3127. if( bc )
  3128. {
  3129. // We need to call the destructor on the true variable type
  3130. int n = GetVariableSlot(offset);
  3131. asASSERT( n >= 0 );
  3132. if( n >= 0 )
  3133. {
  3134. asCDataType dt = variableAllocations[n];
  3135. bool isOnHeap = variableIsOnHeap[n];
  3136. // Call destructor
  3137. CallDestructor(dt, offset, isOnHeap, bc);
  3138. }
  3139. }
  3140. DeallocateVariable(offset);
  3141. }
  3142. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  3143. {
  3144. if( ctx->type.dataType.IsReference() )
  3145. {
  3146. if( ctx->type.dataType.IsObject() )
  3147. {
  3148. ctx->type.dataType.MakeReference(false);
  3149. if( generateCode )
  3150. ctx->bc.Instr(asBC_RDSPtr);
  3151. }
  3152. else
  3153. {
  3154. // This should never happen as primitives are treated differently
  3155. asASSERT(false);
  3156. }
  3157. }
  3158. }
  3159. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  3160. {
  3161. // Temporary variables are assumed to be initialized
  3162. if( type->isTemporary ) return true;
  3163. // Verify that it is a variable
  3164. if( !type->isVariable ) return true;
  3165. // Find the variable
  3166. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  3167. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  3168. if( v == 0 ) return true;
  3169. if( v->isInitialized ) return true;
  3170. // Complex types don't need this test
  3171. if( v->type.IsObject() ) return true;
  3172. // Mark as initialized so that the user will not be bothered again
  3173. v->isInitialized = true;
  3174. // Write warning
  3175. asCString str;
  3176. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  3177. Warning(str.AddressOf(), node);
  3178. return false;
  3179. }
  3180. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  3181. {
  3182. // Check if the variable is initialized (if it indeed is a variable)
  3183. IsVariableInitialized(&ctx->type, node);
  3184. asCDataType to = ctx->type.dataType;
  3185. to.MakeReference(false);
  3186. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  3187. ProcessDeferredParams(ctx);
  3188. }
  3189. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  3190. {
  3191. ProcessPropertyGetAccessor(rctx, node);
  3192. // Make sure the rvalue is initialized if it is a variable
  3193. IsVariableInitialized(&rctx->type, node);
  3194. if( lvalue->IsPrimitive() )
  3195. {
  3196. if( rctx->type.dataType.IsPrimitive() )
  3197. {
  3198. if( rctx->type.dataType.IsReference() )
  3199. {
  3200. // Cannot do implicit conversion of references so we first convert the reference to a variable
  3201. ConvertToVariableNotIn(rctx, lvalueExpr);
  3202. }
  3203. }
  3204. // Implicitly convert the value to the right type
  3205. int l = int(reservedVariables.GetLength());
  3206. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  3207. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  3208. reservedVariables.SetLength(l);
  3209. // Check data type
  3210. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3211. {
  3212. asCString str;
  3213. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3214. Error(str.AddressOf(), node);
  3215. rctx->type.SetDummy();
  3216. }
  3217. // Make sure the rvalue is a variable
  3218. if( !rctx->type.isVariable )
  3219. ConvertToVariableNotIn(rctx, lvalueExpr);
  3220. }
  3221. else
  3222. {
  3223. asCDataType to = *lvalue;
  3224. to.MakeReference(false);
  3225. // TODO: ImplicitConversion should know to do this by itself
  3226. // First convert to a handle which will do a reference cast
  3227. if( !lvalue->IsObjectHandle() &&
  3228. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3229. to.MakeHandle(true);
  3230. // Don't allow the implicit conversion to create an object
  3231. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3232. if( !lvalue->IsObjectHandle() &&
  3233. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3234. {
  3235. // Then convert to a reference, which will validate the handle
  3236. to.MakeHandle(false);
  3237. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3238. }
  3239. // Check data type
  3240. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3241. {
  3242. asCString str;
  3243. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3244. Error(str.AddressOf(), node);
  3245. }
  3246. else
  3247. {
  3248. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3249. if( lvalue->IsObject() )
  3250. asASSERT(!rctx->type.dataType.IsReference());
  3251. }
  3252. }
  3253. }
  3254. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3255. {
  3256. if( !type.isLValue ) return false;
  3257. if( type.dataType.IsReadOnly() ) return false;
  3258. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3259. return true;
  3260. }
  3261. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3262. {
  3263. if( lvalue->dataType.IsReadOnly() )
  3264. {
  3265. Error(TXT_REF_IS_READ_ONLY, node);
  3266. return -1;
  3267. }
  3268. if( lvalue->dataType.IsPrimitive() )
  3269. {
  3270. if( lvalue->isVariable )
  3271. {
  3272. // Copy the value between the variables directly
  3273. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3274. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3275. else
  3276. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3277. // Mark variable as initialized
  3278. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3279. if( v ) v->isInitialized = true;
  3280. }
  3281. else if( lvalue->dataType.IsReference() )
  3282. {
  3283. // Copy the value of the variable to the reference in the register
  3284. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3285. if( s == 1 )
  3286. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3287. else if( s == 2 )
  3288. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3289. else if( s == 4 )
  3290. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3291. else if( s == 8 )
  3292. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3293. }
  3294. else
  3295. {
  3296. Error(TXT_NOT_VALID_LVALUE, node);
  3297. return -1;
  3298. }
  3299. }
  3300. else if( !lvalue->isExplicitHandle )
  3301. {
  3302. asSExprContext ctx(engine);
  3303. ctx.type = *lvalue;
  3304. Dereference(&ctx, true);
  3305. *lvalue = ctx.type;
  3306. bc->AddCode(&ctx.bc);
  3307. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3308. // The beh->copy member will be removed.
  3309. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3310. if( beh->copy )
  3311. {
  3312. // Call the copy operator
  3313. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  3314. bc->Instr(asBC_PshRPtr);
  3315. }
  3316. else
  3317. {
  3318. // Default copy operator
  3319. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3320. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3321. {
  3322. asCString msg;
  3323. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  3324. Error(msg.AddressOf(), node);
  3325. return -1;
  3326. }
  3327. // Copy larger data types from a reference
  3328. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  3329. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3330. }
  3331. }
  3332. else
  3333. {
  3334. // TODO: The object handle can be stored in a variable as well
  3335. if( !lvalue->dataType.IsReference() )
  3336. {
  3337. Error(TXT_NOT_VALID_REFERENCE, node);
  3338. return -1;
  3339. }
  3340. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3341. // Mark variable as initialized
  3342. if( variables )
  3343. {
  3344. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3345. if( v ) v->isInitialized = true;
  3346. }
  3347. }
  3348. return 0;
  3349. }
  3350. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3351. {
  3352. bool conversionDone = false;
  3353. asCArray<int> ops;
  3354. asUINT n;
  3355. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3356. {
  3357. // We need it to be a reference
  3358. if( !ctx->type.dataType.IsReference() )
  3359. {
  3360. asCDataType to = ctx->type.dataType;
  3361. to.MakeReference(true);
  3362. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3363. }
  3364. if( isExplicit )
  3365. {
  3366. // Allow dynamic cast between object handles (only for script objects).
  3367. // At run time this may result in a null handle,
  3368. // which when used will throw an exception
  3369. conversionDone = true;
  3370. if( generateCode )
  3371. {
  3372. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3373. // Allocate a temporary variable for the returned object
  3374. int returnOffset = AllocateVariable(to, true);
  3375. // Move the pointer from the object register to the temporary variable
  3376. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3377. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3378. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3379. ctx->type.SetVariable(to, returnOffset, true);
  3380. ctx->type.dataType.MakeReference(true);
  3381. }
  3382. else
  3383. {
  3384. ctx->type.dataType = to;
  3385. ctx->type.dataType.MakeReference(true);
  3386. }
  3387. }
  3388. else
  3389. {
  3390. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3391. {
  3392. conversionDone = true;
  3393. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3394. }
  3395. }
  3396. }
  3397. else
  3398. {
  3399. // Find a suitable registered behaviour
  3400. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3401. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3402. {
  3403. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3404. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3405. {
  3406. int funcId = beh->operators[n+1];
  3407. // Is the operator for the output type?
  3408. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3409. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3410. continue;
  3411. ops.PushLast(funcId);
  3412. }
  3413. }
  3414. // It shouldn't be possible to have more than one
  3415. asASSERT( ops.GetLength() <= 1 );
  3416. // Should only have one behaviour for each output type
  3417. if( ops.GetLength() == 1 )
  3418. {
  3419. if( generateCode )
  3420. {
  3421. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  3422. // null, we can create a special CALLSYS instruction that checks
  3423. // if the object pointer is null and if so sets the object register
  3424. // to null directly without executing the function.
  3425. //
  3426. // Alternatively I could force the ref cast behaviours be global
  3427. // functions with 1 parameter, even though they should still be
  3428. // registered with RegisterObjectBehaviour()
  3429. // Add code to avoid calling the cast behaviour if the handle is already null,
  3430. // because that will raise a null pointer exception due to the cast behaviour
  3431. // being a class method, and the this pointer cannot be null.
  3432. if( ctx->type.isVariable )
  3433. ctx->bc.Instr(asBC_PopPtr);
  3434. else
  3435. {
  3436. Dereference(ctx, true);
  3437. ConvertToVariable(ctx);
  3438. }
  3439. // TODO: runtime optimize: should have immediate comparison for null pointer
  3440. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  3441. // 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)
  3442. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  3443. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  3444. DeallocateVariable(offset);
  3445. int afterLabel = nextLabel++;
  3446. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3447. // Call the cast operator
  3448. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3449. ctx->bc.Instr(asBC_RDSPtr);
  3450. ctx->type.dataType.MakeReference(false);
  3451. asCTypeInfo objType = ctx->type;
  3452. asCArray<asSExprContext *> args;
  3453. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3454. ctx->bc.Instr(asBC_PopPtr);
  3455. int endLabel = nextLabel++;
  3456. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3457. ctx->bc.Label((short)afterLabel);
  3458. // Make a NULL pointer
  3459. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  3460. ctx->bc.Label((short)endLabel);
  3461. // Since we're receiving a handle, we can release the original variable
  3462. ReleaseTemporaryVariable(objType, &ctx->bc);
  3463. // Push the reference to the handle on the stack
  3464. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3465. }
  3466. else
  3467. {
  3468. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3469. ctx->type.Set(func->returnType);
  3470. }
  3471. }
  3472. else if( ops.GetLength() == 0 )
  3473. {
  3474. // Check for the generic ref cast behaviour
  3475. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3476. {
  3477. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3478. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3479. {
  3480. int funcId = beh->operators[n+1];
  3481. // Does the operator take the ?&out parameter?
  3482. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3483. if( func->parameterTypes.GetLength() != 1 ||
  3484. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3485. func->inOutFlags[0] != asTM_OUTREF )
  3486. continue;
  3487. ops.PushLast(funcId);
  3488. }
  3489. }
  3490. // It shouldn't be possible to have more than one
  3491. asASSERT( ops.GetLength() <= 1 );
  3492. if( ops.GetLength() == 1 )
  3493. {
  3494. if( generateCode )
  3495. {
  3496. asASSERT(to.IsObjectHandle());
  3497. // Allocate a temporary variable of the requested handle type
  3498. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  3499. // Pass the reference of that variable to the function as output parameter
  3500. asCDataType toRef(to);
  3501. toRef.MakeReference(true);
  3502. asCArray<asSExprContext *> args;
  3503. asSExprContext arg(engine);
  3504. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3505. // Don't mark the variable as temporary, so it won't be freed too early
  3506. arg.type.SetVariable(toRef, stackOffset, false);
  3507. arg.type.isLValue = true;
  3508. arg.type.isExplicitHandle = true;
  3509. args.PushLast(&arg);
  3510. asCTypeInfo prev = ctx->type;
  3511. // Call the behaviour method
  3512. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  3513. // Release previous temporary variable
  3514. ReleaseTemporaryVariable(prev, &ctx->bc);
  3515. // Use the reference to the variable as the result of the expression
  3516. // Now we can mark the variable as temporary
  3517. ctx->type.SetVariable(toRef, stackOffset, true);
  3518. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3519. }
  3520. else
  3521. {
  3522. // All casts are legal
  3523. ctx->type.Set(to);
  3524. }
  3525. }
  3526. }
  3527. }
  3528. return conversionDone;
  3529. }
  3530. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3531. {
  3532. asCDataType to = toOrig;
  3533. to.MakeReference(false);
  3534. asASSERT( !ctx->type.dataType.IsReference() );
  3535. // Maybe no conversion is needed
  3536. if( to.IsEqualExceptConst(ctx->type.dataType) )
  3537. {
  3538. // A primitive is const or not
  3539. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3540. return asCC_NO_CONV;
  3541. }
  3542. // Determine the cost of this conversion
  3543. asUINT cost = asCC_NO_CONV;
  3544. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  3545. cost = asCC_INT_FLOAT_CONV;
  3546. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
  3547. cost = asCC_INT_FLOAT_CONV;
  3548. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  3549. cost = asCC_SIGNED_CONV;
  3550. else if( to.IsIntegerType() && (ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
  3551. cost = asCC_SIGNED_CONV;
  3552. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  3553. cost = asCC_PRIMITIVE_SIZE_CONV;
  3554. // Start by implicitly converting constant values
  3555. if( ctx->type.isConstant )
  3556. {
  3557. ImplicitConversionConstant(ctx, to, node, convType);
  3558. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3559. return cost;
  3560. }
  3561. // Allow implicit conversion between numbers
  3562. if( generateCode )
  3563. {
  3564. // When generating the code the decision has already been made, so we don't bother determining the cost
  3565. // Convert smaller types to 32bit first
  3566. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3567. if( s < 4 )
  3568. {
  3569. ConvertToTempVariable(ctx);
  3570. if( ctx->type.dataType.IsIntegerType() )
  3571. {
  3572. if( s == 1 )
  3573. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3574. else if( s == 2 )
  3575. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3576. ctx->type.dataType.SetTokenType(ttInt);
  3577. }
  3578. else if( ctx->type.dataType.IsUnsignedType() )
  3579. {
  3580. if( s == 1 )
  3581. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3582. else if( s == 2 )
  3583. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3584. ctx->type.dataType.SetTokenType(ttUInt);
  3585. }
  3586. }
  3587. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3588. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3589. {
  3590. if( ctx->type.dataType.IsIntegerType() ||
  3591. ctx->type.dataType.IsUnsignedType() ||
  3592. ctx->type.dataType.IsEnumType() )
  3593. {
  3594. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3595. {
  3596. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3597. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3598. }
  3599. else
  3600. {
  3601. ConvertToTempVariable(ctx);
  3602. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3603. int offset = AllocateVariable(to, true);
  3604. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3605. ctx->type.SetVariable(to, offset, true);
  3606. }
  3607. }
  3608. else if( ctx->type.dataType.IsFloatType() )
  3609. {
  3610. ConvertToTempVariable(ctx);
  3611. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3612. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3613. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3614. }
  3615. else if( ctx->type.dataType.IsDoubleType() )
  3616. {
  3617. ConvertToTempVariable(ctx);
  3618. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3619. int offset = AllocateVariable(to, true);
  3620. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3621. ctx->type.SetVariable(to, offset, true);
  3622. }
  3623. // Convert to smaller integer if necessary
  3624. int s = to.GetSizeInMemoryBytes();
  3625. if( s < 4 )
  3626. {
  3627. ConvertToTempVariable(ctx);
  3628. if( s == 1 )
  3629. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3630. else if( s == 2 )
  3631. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3632. }
  3633. }
  3634. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3635. {
  3636. if( ctx->type.dataType.IsIntegerType() ||
  3637. ctx->type.dataType.IsUnsignedType() ||
  3638. ctx->type.dataType.IsEnumType() )
  3639. {
  3640. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3641. {
  3642. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3643. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3644. }
  3645. else
  3646. {
  3647. ConvertToTempVariable(ctx);
  3648. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3649. int offset = AllocateVariable(to, true);
  3650. if( ctx->type.dataType.IsUnsignedType() )
  3651. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3652. else
  3653. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3654. ctx->type.SetVariable(to, offset, true);
  3655. }
  3656. }
  3657. else if( ctx->type.dataType.IsFloatType() )
  3658. {
  3659. ConvertToTempVariable(ctx);
  3660. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3661. int offset = AllocateVariable(to, true);
  3662. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3663. ctx->type.SetVariable(to, offset, true);
  3664. }
  3665. else if( ctx->type.dataType.IsDoubleType() )
  3666. {
  3667. ConvertToTempVariable(ctx);
  3668. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3669. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3670. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3671. }
  3672. }
  3673. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3674. {
  3675. if( ctx->type.dataType.IsIntegerType() ||
  3676. ctx->type.dataType.IsUnsignedType() ||
  3677. ctx->type.dataType.IsEnumType() )
  3678. {
  3679. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3680. {
  3681. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3682. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3683. }
  3684. else
  3685. {
  3686. ConvertToTempVariable(ctx);
  3687. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3688. int offset = AllocateVariable(to, true);
  3689. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3690. ctx->type.SetVariable(to, offset, true);
  3691. }
  3692. }
  3693. else if( ctx->type.dataType.IsFloatType() )
  3694. {
  3695. ConvertToTempVariable(ctx);
  3696. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3697. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3698. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3699. }
  3700. else if( ctx->type.dataType.IsDoubleType() )
  3701. {
  3702. ConvertToTempVariable(ctx);
  3703. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3704. int offset = AllocateVariable(to, true);
  3705. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3706. ctx->type.SetVariable(to, offset, true);
  3707. }
  3708. // Convert to smaller integer if necessary
  3709. int s = to.GetSizeInMemoryBytes();
  3710. if( s < 4 )
  3711. {
  3712. ConvertToTempVariable(ctx);
  3713. if( s == 1 )
  3714. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3715. else if( s == 2 )
  3716. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3717. }
  3718. }
  3719. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3720. {
  3721. if( ctx->type.dataType.IsIntegerType() ||
  3722. ctx->type.dataType.IsUnsignedType() ||
  3723. ctx->type.dataType.IsEnumType() )
  3724. {
  3725. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3726. {
  3727. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3728. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3729. }
  3730. else
  3731. {
  3732. ConvertToTempVariable(ctx);
  3733. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3734. int offset = AllocateVariable(to, true);
  3735. if( ctx->type.dataType.IsUnsignedType() )
  3736. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3737. else
  3738. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3739. ctx->type.SetVariable(to, offset, true);
  3740. }
  3741. }
  3742. else if( ctx->type.dataType.IsFloatType() )
  3743. {
  3744. ConvertToTempVariable(ctx);
  3745. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3746. int offset = AllocateVariable(to, true);
  3747. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3748. ctx->type.SetVariable(to, offset, true);
  3749. }
  3750. else if( ctx->type.dataType.IsDoubleType() )
  3751. {
  3752. ConvertToTempVariable(ctx);
  3753. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3754. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3755. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3756. }
  3757. }
  3758. else if( to.IsFloatType() )
  3759. {
  3760. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3761. {
  3762. ConvertToTempVariable(ctx);
  3763. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3764. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3765. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3766. }
  3767. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3768. {
  3769. ConvertToTempVariable(ctx);
  3770. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3771. int offset = AllocateVariable(to, true);
  3772. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  3773. ctx->type.SetVariable(to, offset, true);
  3774. }
  3775. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3776. {
  3777. ConvertToTempVariable(ctx);
  3778. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  3779. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3780. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3781. }
  3782. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3783. {
  3784. ConvertToTempVariable(ctx);
  3785. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3786. int offset = AllocateVariable(to, true);
  3787. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  3788. ctx->type.SetVariable(to, offset, true);
  3789. }
  3790. else if( ctx->type.dataType.IsDoubleType() )
  3791. {
  3792. ConvertToTempVariable(ctx);
  3793. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3794. int offset = AllocateVariable(to, true);
  3795. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  3796. ctx->type.SetVariable(to, offset, true);
  3797. }
  3798. }
  3799. else if( to.IsDoubleType() )
  3800. {
  3801. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3802. {
  3803. ConvertToTempVariable(ctx);
  3804. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3805. int offset = AllocateVariable(to, true);
  3806. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  3807. ctx->type.SetVariable(to, offset, true);
  3808. }
  3809. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3810. {
  3811. ConvertToTempVariable(ctx);
  3812. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  3813. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3814. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3815. }
  3816. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3817. {
  3818. ConvertToTempVariable(ctx);
  3819. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3820. int offset = AllocateVariable(to, true);
  3821. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  3822. ctx->type.SetVariable(to, offset, true);
  3823. }
  3824. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3825. {
  3826. ConvertToTempVariable(ctx);
  3827. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  3828. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3829. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3830. }
  3831. else if( ctx->type.dataType.IsFloatType() )
  3832. {
  3833. ConvertToTempVariable(ctx);
  3834. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3835. int offset = AllocateVariable(to, true);
  3836. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  3837. ctx->type.SetVariable(to, offset, true);
  3838. }
  3839. }
  3840. }
  3841. else
  3842. {
  3843. if( (to.IsIntegerType() || to.IsUnsignedType() ||
  3844. to.IsFloatType() || to.IsDoubleType() ||
  3845. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  3846. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  3847. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
  3848. ctx->type.dataType.IsEnumType()) )
  3849. {
  3850. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3851. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3852. }
  3853. }
  3854. // Primitive types on the stack, can be const or non-const
  3855. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3856. return cost;
  3857. }
  3858. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  3859. {
  3860. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  3861. ctx->type.dataType.IsNullHandle() );
  3862. // No conversion from void to any other type
  3863. if( ctx->type.dataType.GetTokenType() == ttVoid )
  3864. return asCC_NO_CONV;
  3865. // Do we want a var type?
  3866. if( to.GetTokenType() == ttQuestion )
  3867. {
  3868. // Any type can be converted to a var type, but only when not generating code
  3869. asASSERT( !generateCode );
  3870. ctx->type.dataType = to;
  3871. return asCC_VARIABLE_CONV;
  3872. }
  3873. // Do we want a primitive?
  3874. else if( to.IsPrimitive() )
  3875. {
  3876. if( !ctx->type.dataType.IsPrimitive() )
  3877. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  3878. else
  3879. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  3880. }
  3881. else // The target is a complex type
  3882. {
  3883. if( ctx->type.dataType.IsPrimitive() )
  3884. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  3885. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  3886. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  3887. }
  3888. return asCC_NO_CONV;
  3889. }
  3890. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3891. {
  3892. if( ctx->type.isExplicitHandle )
  3893. {
  3894. // An explicit handle cannot be converted to a primitive
  3895. if( convType != asIC_IMPLICIT_CONV && node )
  3896. {
  3897. asCString str;
  3898. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3899. Error(str.AddressOf(), node);
  3900. }
  3901. return asCC_NO_CONV;
  3902. }
  3903. // TODO: Must use the const cast behaviour if the object is read-only
  3904. // Find matching value cast behaviours
  3905. // Here we're only interested in those that convert the type to a primitive type
  3906. asCArray<int> funcs;
  3907. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3908. if( beh )
  3909. {
  3910. if( convType == asIC_EXPLICIT_VAL_CAST )
  3911. {
  3912. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3913. {
  3914. // accept both implicit and explicit cast
  3915. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3916. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3917. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3918. funcs.PushLast(beh->operators[n+1]);
  3919. }
  3920. }
  3921. else
  3922. {
  3923. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3924. {
  3925. // accept only implicit cast
  3926. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3927. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3928. funcs.PushLast(beh->operators[n+1]);
  3929. }
  3930. }
  3931. }
  3932. // This matrix describes the priorities of the types to search for, for each target type
  3933. // The first column is the target type, the priorities goes from left to right
  3934. eTokenType matchMtx[10][10] =
  3935. {
  3936. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3937. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3938. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3939. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3940. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3941. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3942. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  3943. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  3944. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  3945. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  3946. };
  3947. // Which row to use?
  3948. eTokenType *row = 0;
  3949. for( unsigned int type = 0; type < 10; type++ )
  3950. {
  3951. if( to.GetTokenType() == matchMtx[type][0] )
  3952. {
  3953. row = &matchMtx[type][0];
  3954. break;
  3955. }
  3956. }
  3957. // Find the best matching cast operator
  3958. int funcId = 0;
  3959. if( row )
  3960. {
  3961. asCDataType target(to);
  3962. // Priority goes from left to right in the matrix
  3963. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  3964. {
  3965. target.SetTokenType(row[attempt]);
  3966. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3967. {
  3968. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  3969. if( descr->returnType.IsEqualExceptConst(target) )
  3970. {
  3971. funcId = funcs[n];
  3972. break;
  3973. }
  3974. }
  3975. }
  3976. }
  3977. // Did we find a suitable function?
  3978. if( funcId != 0 )
  3979. {
  3980. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  3981. if( generateCode )
  3982. {
  3983. asCTypeInfo objType = ctx->type;
  3984. Dereference(ctx, true);
  3985. PerformFunctionCall(funcId, ctx);
  3986. ReleaseTemporaryVariable(objType, &ctx->bc);
  3987. }
  3988. else
  3989. ctx->type.Set(descr->returnType);
  3990. // Allow one more implicit conversion to another primitive type
  3991. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  3992. }
  3993. else
  3994. {
  3995. if( convType != asIC_IMPLICIT_CONV && node )
  3996. {
  3997. asCString str;
  3998. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3999. Error(str.AddressOf(), node);
  4000. }
  4001. }
  4002. return asCC_NO_CONV;
  4003. }
  4004. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4005. {
  4006. // Convert null to any object type handle, but not to a non-handle type
  4007. if( ctx->type.IsNullConstant() )
  4008. {
  4009. if( to.IsObjectHandle() )
  4010. {
  4011. ctx->type.dataType = to;
  4012. return asCC_REF_CONV;
  4013. }
  4014. return asCC_NO_CONV;
  4015. }
  4016. asASSERT(ctx->type.dataType.GetObjectType());
  4017. // First attempt to convert the base type without instanciating another instance
  4018. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4019. {
  4020. // If the to type is an interface and the from type implements it, then we can convert it immediately
  4021. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  4022. {
  4023. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4024. return asCC_REF_CONV;
  4025. }
  4026. // If the to type is a class and the from type derives from it, then we can convert it immediately
  4027. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4028. {
  4029. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4030. return asCC_REF_CONV;
  4031. }
  4032. // If the types are not equal yet, then we may still be able to find a reference cast
  4033. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  4034. {
  4035. // A ref cast must not remove the constness
  4036. bool isConst = false;
  4037. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  4038. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  4039. isConst = true;
  4040. // We may still be able to find an implicit ref cast behaviour
  4041. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  4042. ctx->type.dataType.MakeHandleToConst(isConst);
  4043. // Was the conversion done?
  4044. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  4045. return asCC_REF_CONV;
  4046. }
  4047. }
  4048. // Convert matching function types
  4049. if( to.GetFuncDef() && ctx->type.dataType.GetFuncDef() &&
  4050. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  4051. {
  4052. asCScriptFunction *toFunc = to.GetFuncDef();
  4053. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  4054. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  4055. {
  4056. ctx->type.dataType.SetFuncDef(toFunc);
  4057. return asCC_REF_CONV;
  4058. }
  4059. }
  4060. return asCC_NO_CONV;
  4061. }
  4062. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv convType, bool generateCode)
  4063. {
  4064. asUINT cost = asCC_NO_CONV;
  4065. // If the base type is still different, and we are allowed to instance
  4066. // another object then we can try an implicit value cast
  4067. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4068. {
  4069. // TODO: Implement support for implicit constructor/factory
  4070. asCArray<int> funcs;
  4071. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4072. if( beh )
  4073. {
  4074. if( convType == asIC_EXPLICIT_VAL_CAST )
  4075. {
  4076. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4077. {
  4078. // accept both implicit and explicit cast
  4079. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4080. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4081. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4082. funcs.PushLast(beh->operators[n+1]);
  4083. }
  4084. }
  4085. else
  4086. {
  4087. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4088. {
  4089. // accept only implicit cast
  4090. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4091. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4092. funcs.PushLast(beh->operators[n+1]);
  4093. }
  4094. }
  4095. }
  4096. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  4097. asASSERT( funcs.GetLength() <= 1 );
  4098. if( funcs.GetLength() == 1 )
  4099. {
  4100. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  4101. if( generateCode )
  4102. {
  4103. asCTypeInfo objType = ctx->type;
  4104. Dereference(ctx, true);
  4105. bool useVariable = false;
  4106. int stackOffset = 0;
  4107. if( f->DoesReturnOnStack() )
  4108. {
  4109. useVariable = true;
  4110. stackOffset = AllocateVariable(f->returnType, true);
  4111. // Push the pointer to the pre-allocated space for the return value
  4112. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  4113. // The object pointer is already on the stack, but should be the top
  4114. // one, so we need to swap the pointers in order to get the correct
  4115. ctx->bc.Instr(asBC_SwapPtr);
  4116. }
  4117. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  4118. ReleaseTemporaryVariable(objType, &ctx->bc);
  4119. }
  4120. else
  4121. ctx->type.Set(f->returnType);
  4122. cost = asCC_TO_OBJECT_CONV;
  4123. }
  4124. }
  4125. return cost;
  4126. }
  4127. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4128. {
  4129. // First try a ref cast
  4130. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  4131. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  4132. // construct the object through any of the available constructors
  4133. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4134. {
  4135. asCArray<int> funcs;
  4136. funcs = to.GetObjectType()->beh.constructors;
  4137. asCArray<asSExprContext *> args;
  4138. args.PushLast(ctx);
  4139. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, false, true, false);
  4140. // Did we find a matching constructor?
  4141. if( funcs.GetLength() == 1 )
  4142. {
  4143. if( generateCode )
  4144. {
  4145. // TODO: This should really reuse the code from CompileConstructCall
  4146. // Allocate the new object
  4147. asCTypeInfo tempObj;
  4148. tempObj.dataType = to;
  4149. tempObj.dataType.MakeReference(false);
  4150. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  4151. tempObj.dataType.MakeReference(true);
  4152. tempObj.isTemporary = true;
  4153. tempObj.isVariable = true;
  4154. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4155. // Push the address of the object on the stack
  4156. asSExprContext e(engine);
  4157. if( onHeap )
  4158. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4159. PrepareFunctionCall(funcs[0], &e.bc, args);
  4160. MoveArgsToStack(funcs[0], &e.bc, args, false);
  4161. // If the object is allocated on the stack, then call the constructor as a normal function
  4162. if( onHeap )
  4163. {
  4164. int offset = 0;
  4165. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4166. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  4167. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4168. }
  4169. else
  4170. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4171. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  4172. // Add tag that the object has been initialized
  4173. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4174. // The constructor doesn't return anything,
  4175. // so we have to manually inform the type of
  4176. // the return value
  4177. e.type = tempObj;
  4178. if( !onHeap )
  4179. e.type.dataType.MakeReference(false);
  4180. // Push the address of the object on the stack again
  4181. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4182. MergeExprBytecodeAndType(ctx, &e);
  4183. }
  4184. else
  4185. {
  4186. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  4187. }
  4188. }
  4189. }
  4190. // If the base type is still different, and we are allowed to instance
  4191. // another object then we can try an implicit value cast
  4192. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4193. {
  4194. // Attempt implicit value cast
  4195. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  4196. }
  4197. // If we still haven't converted the base type to the correct type, then there is
  4198. // no need to continue as it is not possible to do the conversion
  4199. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4200. return asCC_NO_CONV;
  4201. if( to.IsObjectHandle() )
  4202. {
  4203. // There is no extra cost in converting to a handle
  4204. // reference to handle -> handle
  4205. // reference -> handle
  4206. // object -> handle
  4207. // handle -> reference to handle
  4208. // reference -> reference to handle
  4209. // object -> reference to handle
  4210. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  4211. // If the rvalue is a handle to a const object, then
  4212. // the lvalue must also be a handle to a const object
  4213. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  4214. {
  4215. if( convType != asIC_IMPLICIT_CONV )
  4216. {
  4217. asASSERT(node);
  4218. asCString str;
  4219. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4220. Error(str.AddressOf(), node);
  4221. }
  4222. }
  4223. if( !ctx->type.dataType.IsObjectHandle() )
  4224. {
  4225. // An object type can be directly converted to a handle of the
  4226. // same type by doing a ref copy to a new variable
  4227. if( ctx->type.dataType.SupportHandles() )
  4228. {
  4229. asCDataType dt = ctx->type.dataType;
  4230. dt.MakeHandle(true);
  4231. dt.MakeReference(false);
  4232. if( generateCode )
  4233. {
  4234. // TODO: runtime optimize: This copy is not always necessary.
  4235. // How to determine when not to do it?
  4236. int offset = AllocateVariable(dt, true);
  4237. if( ctx->type.dataType.IsReference() )
  4238. ctx->bc.Instr(asBC_RDSPtr);
  4239. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4240. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  4241. ctx->bc.Instr(asBC_PopPtr);
  4242. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4243. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4244. if( to.IsReference() )
  4245. dt.MakeReference(true);
  4246. else
  4247. ctx->bc.Instr(asBC_RDSPtr);
  4248. ctx->type.SetVariable(dt, offset, true);
  4249. }
  4250. else
  4251. ctx->type.dataType = dt;
  4252. // When this conversion is done the expression is no longer an lvalue
  4253. ctx->type.isLValue = false;
  4254. }
  4255. if( ctx->type.dataType.IsObjectHandle() )
  4256. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4257. if( to.IsHandleToConst() && ctx->type.dataType.IsObjectHandle() )
  4258. ctx->type.dataType.MakeHandleToConst(true);
  4259. }
  4260. else
  4261. {
  4262. // A handle to non-const can be converted to a
  4263. // handle to const, but not the other way
  4264. if( to.IsHandleToConst() )
  4265. ctx->type.dataType.MakeHandleToConst(true);
  4266. // A const handle can be converted to a non-const
  4267. // handle and vice versa as the handle is just a value
  4268. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4269. }
  4270. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4271. {
  4272. if( generateCode )
  4273. {
  4274. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4275. // If the input type is a handle, then a simple ref copy is enough
  4276. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4277. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  4278. // If the input type is read-only we'll need to temporarily
  4279. // remove this constness, otherwise the assignment will fail
  4280. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4281. ctx->type.dataType.MakeReadOnly(false);
  4282. // If the object already is a temporary variable, then the copy
  4283. // doesn't have to be made as it is already a unique object
  4284. PrepareTemporaryObject(node, ctx);
  4285. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4286. ctx->type.isExplicitHandle = isExplicitHandle;
  4287. }
  4288. // A non-reference can be converted to a reference,
  4289. // by putting the value in a temporary variable
  4290. ctx->type.dataType.MakeReference(true);
  4291. // Since it is a new temporary variable it doesn't have to be const
  4292. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4293. }
  4294. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  4295. {
  4296. Dereference(ctx, generateCode);
  4297. }
  4298. }
  4299. else
  4300. {
  4301. if( !to.IsReference() )
  4302. {
  4303. // reference to handle -> object
  4304. // handle -> object
  4305. // reference -> object
  4306. // An implicit handle can be converted to an object by adding a check for null pointer
  4307. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4308. {
  4309. if( generateCode )
  4310. ctx->bc.Instr(asBC_CHKREF);
  4311. ctx->type.dataType.MakeHandle(false);
  4312. }
  4313. // A const object can be converted to a non-const object through a copy
  4314. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  4315. allowObjectConstruct )
  4316. {
  4317. // Does the object type allow a copy to be made?
  4318. if( ctx->type.dataType.CanBeCopied() )
  4319. {
  4320. if( generateCode )
  4321. {
  4322. // Make a temporary object with the copy
  4323. PrepareTemporaryObject(node, ctx);
  4324. }
  4325. // In case the object was already in a temporary variable, then the function
  4326. // didn't really do anything so we need to remove the constness here
  4327. ctx->type.dataType.MakeReadOnly(false);
  4328. // Add the cost for the copy
  4329. cost += asCC_TO_OBJECT_CONV;
  4330. }
  4331. }
  4332. if( ctx->type.dataType.IsReference() )
  4333. {
  4334. // This may look strange, but a value type allocated on the stack is already
  4335. // correct, so nothing should be done other than remove the mark as reference.
  4336. // For types allocated on the heap, it is necessary to dereference the pointer
  4337. // that is currently on the stack
  4338. if( IsVariableOnHeap(ctx->type.stackOffset) )
  4339. Dereference(ctx, generateCode);
  4340. else
  4341. ctx->type.dataType.MakeReference(false);
  4342. }
  4343. // A non-const object can be converted to a const object directly
  4344. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4345. {
  4346. ctx->type.dataType.MakeReadOnly(true);
  4347. }
  4348. }
  4349. else
  4350. {
  4351. // reference to handle -> reference
  4352. // handle -> reference
  4353. // object -> reference
  4354. if( ctx->type.dataType.IsReference() )
  4355. {
  4356. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4357. {
  4358. // ASHANDLE objects are really value types, so explicit handle can be removed
  4359. ctx->type.isExplicitHandle = false;
  4360. ctx->type.dataType.MakeHandle(false);
  4361. }
  4362. // A reference to a handle can be converted to a reference to an object
  4363. // by first reading the address, then verifying that it is not null
  4364. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4365. {
  4366. ctx->type.dataType.MakeHandle(false);
  4367. if( generateCode )
  4368. ctx->bc.Instr(asBC_ChkRefS);
  4369. }
  4370. // A reference to a non-const can be converted to a reference to a const
  4371. if( to.IsReadOnly() )
  4372. ctx->type.dataType.MakeReadOnly(true);
  4373. else if( ctx->type.dataType.IsReadOnly() )
  4374. {
  4375. // A reference to a const can be converted to a reference to a
  4376. // non-const by copying the object to a temporary variable
  4377. ctx->type.dataType.MakeReadOnly(false);
  4378. if( generateCode )
  4379. {
  4380. // If the object already is a temporary variable, then the copy
  4381. // doesn't have to be made as it is already a unique object
  4382. PrepareTemporaryObject(node, ctx);
  4383. }
  4384. // Add the cost for the copy
  4385. cost += asCC_TO_OBJECT_CONV;
  4386. }
  4387. }
  4388. else
  4389. {
  4390. // A value type allocated on the stack is differentiated
  4391. // by it not being a reference. But it can be handled as
  4392. // reference by pushing the pointer on the stack
  4393. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  4394. (ctx->type.isVariable || ctx->type.isTemporary) &&
  4395. !IsVariableOnHeap(ctx->type.stackOffset) )
  4396. {
  4397. // Actually the pointer is already pushed on the stack in
  4398. // CompileVariableAccess, so we don't need to do anything else
  4399. }
  4400. else if( generateCode )
  4401. {
  4402. // A non-reference can be converted to a reference,
  4403. // by putting the value in a temporary variable
  4404. // If the input type is read-only we'll need to temporarily
  4405. // remove this constness, otherwise the assignment will fail
  4406. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4407. ctx->type.dataType.MakeReadOnly(false);
  4408. // If the object already is a temporary variable, then the copy
  4409. // doesn't have to be made as it is already a unique object
  4410. PrepareTemporaryObject(node, ctx);
  4411. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4412. // Add the cost for the copy
  4413. cost += asCC_TO_OBJECT_CONV;
  4414. }
  4415. // A handle can be converted to a reference, by checking for a null pointer
  4416. if( ctx->type.dataType.IsObjectHandle() )
  4417. {
  4418. if( generateCode )
  4419. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4420. ctx->type.dataType.MakeHandle(false);
  4421. ctx->type.dataType.MakeReference(true);
  4422. // TODO: Make sure a handle to const isn't converted to non-const reference
  4423. }
  4424. else
  4425. {
  4426. // This may look strange as the conversion was to make the expression a reference
  4427. // but a value type allocated on the stack is a reference even without the type
  4428. // being marked as such.
  4429. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4430. }
  4431. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  4432. // Since it is a new temporary variable it doesn't have to be const
  4433. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4434. }
  4435. }
  4436. }
  4437. return cost;
  4438. }
  4439. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, bool /*allowObjectConstruct*/)
  4440. {
  4441. // TODO: This function should call the constructor/factory that has been marked as available
  4442. // for implicit conversions. The code will likely be similar to CallCopyConstructor()
  4443. return asCC_NO_CONV;
  4444. }
  4445. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  4446. {
  4447. asASSERT(from->type.isConstant);
  4448. // TODO: node should be the node of the value that is
  4449. // converted (not the operator that provokes the implicit
  4450. // conversion)
  4451. // If the base type is correct there is no more to do
  4452. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  4453. // References cannot be constants
  4454. if( from->type.dataType.IsReference() ) return;
  4455. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  4456. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4457. {
  4458. if( from->type.dataType.IsFloatType() ||
  4459. from->type.dataType.IsDoubleType() ||
  4460. from->type.dataType.IsUnsignedType() ||
  4461. from->type.dataType.IsIntegerType() ||
  4462. from->type.dataType.IsEnumType() )
  4463. {
  4464. // Transform the value
  4465. // Float constants can be implicitly converted to int
  4466. if( from->type.dataType.IsFloatType() )
  4467. {
  4468. float fc = from->type.floatValue;
  4469. int ic = int(fc);
  4470. if( float(ic) != fc )
  4471. {
  4472. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4473. }
  4474. from->type.intValue = ic;
  4475. }
  4476. // Double constants can be implicitly converted to int
  4477. else if( from->type.dataType.IsDoubleType() )
  4478. {
  4479. double fc = from->type.doubleValue;
  4480. int ic = int(fc);
  4481. if( double(ic) != fc )
  4482. {
  4483. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4484. }
  4485. from->type.intValue = ic;
  4486. }
  4487. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4488. {
  4489. // Verify that it is possible to convert to signed without getting negative
  4490. if( from->type.intValue < 0 )
  4491. {
  4492. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4493. }
  4494. // Convert to 32bit
  4495. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4496. from->type.intValue = from->type.byteValue;
  4497. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4498. from->type.intValue = from->type.wordValue;
  4499. }
  4500. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4501. {
  4502. // Convert to 32bit
  4503. from->type.intValue = int(from->type.qwordValue);
  4504. }
  4505. else if( from->type.dataType.IsIntegerType() &&
  4506. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4507. {
  4508. // Convert to 32bit
  4509. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4510. from->type.intValue = (signed char)from->type.byteValue;
  4511. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4512. from->type.intValue = (short)from->type.wordValue;
  4513. }
  4514. else if( from->type.dataType.IsEnumType() )
  4515. {
  4516. // Enum type is already an integer type
  4517. }
  4518. // Set the resulting type
  4519. if( to.IsEnumType() )
  4520. from->type.dataType = to;
  4521. else
  4522. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4523. }
  4524. // Check if a downsize is necessary
  4525. if( to.IsIntegerType() &&
  4526. from->type.dataType.IsIntegerType() &&
  4527. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4528. {
  4529. // Verify if it is possible
  4530. if( to.GetSizeInMemoryBytes() == 1 )
  4531. {
  4532. if( char(from->type.intValue) != from->type.intValue )
  4533. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4534. from->type.byteValue = char(from->type.intValue);
  4535. }
  4536. else if( to.GetSizeInMemoryBytes() == 2 )
  4537. {
  4538. if( short(from->type.intValue) != from->type.intValue )
  4539. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4540. from->type.wordValue = short(from->type.intValue);
  4541. }
  4542. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4543. }
  4544. }
  4545. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4546. {
  4547. // Float constants can be implicitly converted to int
  4548. if( from->type.dataType.IsFloatType() )
  4549. {
  4550. float fc = from->type.floatValue;
  4551. asINT64 ic = asINT64(fc);
  4552. if( float(ic) != fc )
  4553. {
  4554. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4555. }
  4556. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4557. from->type.qwordValue = ic;
  4558. }
  4559. // Double constants can be implicitly converted to int
  4560. else if( from->type.dataType.IsDoubleType() )
  4561. {
  4562. double fc = from->type.doubleValue;
  4563. asINT64 ic = asINT64(fc);
  4564. if( double(ic) != fc )
  4565. {
  4566. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4567. }
  4568. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4569. from->type.qwordValue = ic;
  4570. }
  4571. else if( from->type.dataType.IsUnsignedType() )
  4572. {
  4573. // Convert to 64bit
  4574. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4575. from->type.qwordValue = from->type.byteValue;
  4576. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4577. from->type.qwordValue = from->type.wordValue;
  4578. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4579. from->type.qwordValue = from->type.dwordValue;
  4580. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  4581. {
  4582. if( asINT64(from->type.qwordValue) < 0 )
  4583. {
  4584. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4585. }
  4586. }
  4587. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4588. }
  4589. else if( from->type.dataType.IsEnumType() )
  4590. {
  4591. from->type.qwordValue = from->type.intValue;
  4592. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4593. }
  4594. else if( from->type.dataType.IsIntegerType() )
  4595. {
  4596. // Convert to 64bit
  4597. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4598. from->type.qwordValue = (signed char)from->type.byteValue;
  4599. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4600. from->type.qwordValue = (short)from->type.wordValue;
  4601. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4602. from->type.qwordValue = from->type.intValue;
  4603. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4604. }
  4605. }
  4606. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4607. {
  4608. if( from->type.dataType.IsFloatType() )
  4609. {
  4610. float fc = from->type.floatValue;
  4611. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  4612. // To maintain a consistent behaviour across compilers we convert to int first.
  4613. asUINT uic = asUINT(int(fc));
  4614. if( float(uic) != fc )
  4615. {
  4616. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4617. }
  4618. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4619. from->type.intValue = uic;
  4620. // Try once more, in case of a smaller type
  4621. ImplicitConversionConstant(from, to, node, convType);
  4622. }
  4623. else if( from->type.dataType.IsDoubleType() )
  4624. {
  4625. double fc = from->type.doubleValue;
  4626. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  4627. // To maintain a consistent behaviour across compilers we convert to int first.
  4628. asUINT uic = asUINT(int(fc));
  4629. if( double(uic) != fc )
  4630. {
  4631. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4632. }
  4633. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4634. from->type.intValue = uic;
  4635. // Try once more, in case of a smaller type
  4636. ImplicitConversionConstant(from, to, node, convType);
  4637. }
  4638. else if( from->type.dataType.IsEnumType() )
  4639. {
  4640. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4641. // Try once more, in case of a smaller type
  4642. ImplicitConversionConstant(from, to, node, convType);
  4643. }
  4644. else if( from->type.dataType.IsIntegerType() )
  4645. {
  4646. // Verify that it is possible to convert to unsigned without loosing negative
  4647. if( from->type.intValue < 0 )
  4648. {
  4649. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4650. }
  4651. // Convert to 32bit
  4652. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4653. from->type.intValue = (signed char)from->type.byteValue;
  4654. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4655. from->type.intValue = (short)from->type.wordValue;
  4656. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4657. // Try once more, in case of a smaller type
  4658. ImplicitConversionConstant(from, to, node, convType);
  4659. }
  4660. else if( from->type.dataType.IsUnsignedType() &&
  4661. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4662. {
  4663. // Convert to 32bit
  4664. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4665. from->type.dwordValue = from->type.byteValue;
  4666. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4667. from->type.dwordValue = from->type.wordValue;
  4668. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4669. // Try once more, in case of a smaller type
  4670. ImplicitConversionConstant(from, to, node, convType);
  4671. }
  4672. else if( from->type.dataType.IsUnsignedType() &&
  4673. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4674. {
  4675. // Verify if it is possible
  4676. if( to.GetSizeInMemoryBytes() == 1 )
  4677. {
  4678. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  4679. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4680. from->type.byteValue = asBYTE(from->type.dwordValue);
  4681. }
  4682. else if( to.GetSizeInMemoryBytes() == 2 )
  4683. {
  4684. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  4685. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4686. from->type.wordValue = asWORD(from->type.dwordValue);
  4687. }
  4688. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4689. }
  4690. }
  4691. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4692. {
  4693. if( from->type.dataType.IsFloatType() )
  4694. {
  4695. float fc = from->type.floatValue;
  4696. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4697. asQWORD uic = asQWORD(asINT64(fc));
  4698. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4699. // MSVC6 doesn't support this conversion
  4700. if( float(uic) != fc )
  4701. {
  4702. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4703. }
  4704. #endif
  4705. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4706. from->type.qwordValue = uic;
  4707. }
  4708. else if( from->type.dataType.IsDoubleType() )
  4709. {
  4710. double fc = from->type.doubleValue;
  4711. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4712. asQWORD uic = asQWORD(asINT64(fc));
  4713. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4714. // MSVC6 doesn't support this conversion
  4715. if( double(uic) != fc )
  4716. {
  4717. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4718. }
  4719. #endif
  4720. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4721. from->type.qwordValue = uic;
  4722. }
  4723. else if( from->type.dataType.IsEnumType() )
  4724. {
  4725. from->type.qwordValue = (asINT64)from->type.intValue;
  4726. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4727. }
  4728. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4729. {
  4730. // Convert to 64bit
  4731. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4732. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  4733. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4734. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  4735. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4736. from->type.qwordValue = (asINT64)from->type.intValue;
  4737. // Verify that it is possible to convert to unsigned without loosing negative
  4738. if( asINT64(from->type.qwordValue) < 0 )
  4739. {
  4740. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4741. }
  4742. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4743. }
  4744. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4745. {
  4746. // Verify that it is possible to convert to unsigned without loosing negative
  4747. if( asINT64(from->type.qwordValue) < 0 )
  4748. {
  4749. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4750. }
  4751. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4752. }
  4753. else if( from->type.dataType.IsUnsignedType() )
  4754. {
  4755. // Convert to 64bit
  4756. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4757. from->type.qwordValue = from->type.byteValue;
  4758. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4759. from->type.qwordValue = from->type.wordValue;
  4760. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4761. from->type.qwordValue = from->type.dwordValue;
  4762. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4763. }
  4764. }
  4765. else if( to.IsFloatType() )
  4766. {
  4767. if( from->type.dataType.IsDoubleType() )
  4768. {
  4769. double ic = from->type.doubleValue;
  4770. float fc = float(ic);
  4771. // Don't bother warning about this
  4772. // if( double(fc) != ic )
  4773. // {
  4774. // asCString str;
  4775. // str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  4776. // if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str.AddressOf(), node);
  4777. // }
  4778. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4779. from->type.floatValue = fc;
  4780. }
  4781. else if( from->type.dataType.IsEnumType() )
  4782. {
  4783. float fc = float(from->type.intValue);
  4784. if( int(fc) != from->type.intValue )
  4785. {
  4786. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4787. }
  4788. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4789. from->type.floatValue = fc;
  4790. }
  4791. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4792. {
  4793. // Must properly convert value in case the from value is smaller
  4794. int ic;
  4795. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4796. ic = (signed char)from->type.byteValue;
  4797. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4798. ic = (short)from->type.wordValue;
  4799. else
  4800. ic = from->type.intValue;
  4801. float fc = float(ic);
  4802. if( int(fc) != ic )
  4803. {
  4804. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4805. }
  4806. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4807. from->type.floatValue = fc;
  4808. }
  4809. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4810. {
  4811. float fc = float(asINT64(from->type.qwordValue));
  4812. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4813. {
  4814. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4815. }
  4816. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4817. from->type.floatValue = fc;
  4818. }
  4819. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4820. {
  4821. // Must properly convert value in case the from value is smaller
  4822. unsigned int uic;
  4823. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4824. uic = from->type.byteValue;
  4825. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4826. uic = from->type.wordValue;
  4827. else
  4828. uic = from->type.dwordValue;
  4829. float fc = float(uic);
  4830. if( (unsigned int)(fc) != uic )
  4831. {
  4832. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4833. }
  4834. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4835. from->type.floatValue = fc;
  4836. }
  4837. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4838. {
  4839. float fc = float((asINT64)from->type.qwordValue);
  4840. if( asQWORD(fc) != from->type.qwordValue )
  4841. {
  4842. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4843. }
  4844. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4845. from->type.floatValue = fc;
  4846. }
  4847. }
  4848. else if( to.IsDoubleType() )
  4849. {
  4850. if( from->type.dataType.IsFloatType() )
  4851. {
  4852. float ic = from->type.floatValue;
  4853. double fc = double(ic);
  4854. // Don't check for float->double
  4855. // if( float(fc) != ic )
  4856. // {
  4857. // acCString str;
  4858. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  4859. // if( !isExplicit ) Warning(str, node);
  4860. // }
  4861. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4862. from->type.doubleValue = fc;
  4863. }
  4864. else if( from->type.dataType.IsEnumType() )
  4865. {
  4866. double fc = double(from->type.intValue);
  4867. if( int(fc) != from->type.intValue )
  4868. {
  4869. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4870. }
  4871. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4872. from->type.doubleValue = fc;
  4873. }
  4874. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4875. {
  4876. // Must properly convert value in case the from value is smaller
  4877. int ic;
  4878. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4879. ic = (signed char)from->type.byteValue;
  4880. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4881. ic = (short)from->type.wordValue;
  4882. else
  4883. ic = from->type.intValue;
  4884. double fc = double(ic);
  4885. if( int(fc) != ic )
  4886. {
  4887. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4888. }
  4889. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4890. from->type.doubleValue = fc;
  4891. }
  4892. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4893. {
  4894. double fc = double(asINT64(from->type.qwordValue));
  4895. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4896. {
  4897. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4898. }
  4899. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4900. from->type.doubleValue = fc;
  4901. }
  4902. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4903. {
  4904. // Must properly convert value in case the from value is smaller
  4905. unsigned int uic;
  4906. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4907. uic = from->type.byteValue;
  4908. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4909. uic = from->type.wordValue;
  4910. else
  4911. uic = from->type.dwordValue;
  4912. double fc = double(uic);
  4913. if( (unsigned int)(fc) != uic )
  4914. {
  4915. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4916. }
  4917. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4918. from->type.doubleValue = fc;
  4919. }
  4920. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4921. {
  4922. double fc = double((asINT64)from->type.qwordValue);
  4923. if( asQWORD(fc) != from->type.qwordValue )
  4924. {
  4925. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4926. }
  4927. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4928. from->type.doubleValue = fc;
  4929. }
  4930. }
  4931. }
  4932. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  4933. {
  4934. // Implicit handle types should always be treated as handles in assignments
  4935. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4936. {
  4937. lctx->type.dataType.MakeHandle(true);
  4938. lctx->type.isExplicitHandle = true;
  4939. }
  4940. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  4941. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  4942. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  4943. !lctx->type.dataType.GetBehaviour()->copy)
  4944. lctx->type.isExplicitHandle = true;
  4945. // If the left hand expression is a property accessor, then that should be used
  4946. // to do the assignment instead of the ordinary operator. The exception is when
  4947. // the property accessor is for a handle property, and the operation is a value
  4948. // assignment.
  4949. if( (lctx->property_get || lctx->property_set) &&
  4950. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  4951. {
  4952. if( op != ttAssignment )
  4953. {
  4954. // TODO: getset: We may actually be able to support this, if we can
  4955. // guarantee that the object reference will stay valid
  4956. // between the calls to the get and set accessors.
  4957. // Process the property to free the memory
  4958. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4959. // Compound assignments are not allowed for properties
  4960. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  4961. return -1;
  4962. }
  4963. // It is not allowed to do a handle assignment on a property
  4964. // accessor that doesn't take a handle in the set accessor.
  4965. if( lctx->property_set && lctx->type.isExplicitHandle )
  4966. {
  4967. // set_opIndex has 2 arguments, where as normal setters have only 1
  4968. asCArray<asCDataType>& parameterTypes =
  4969. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  4970. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  4971. {
  4972. // Process the property to free the memory
  4973. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4974. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  4975. return -1;
  4976. }
  4977. }
  4978. MergeExprBytecodeAndType(ctx, lctx);
  4979. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  4980. }
  4981. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4982. {
  4983. // Get the handle to the object that will be used for the value assignment
  4984. ProcessPropertyGetAccessor(lctx, opNode);
  4985. }
  4986. if( lctx->type.dataType.IsPrimitive() )
  4987. {
  4988. if( !lctx->type.isLValue )
  4989. {
  4990. Error(TXT_NOT_LVALUE, lexpr);
  4991. return -1;
  4992. }
  4993. if( op != ttAssignment )
  4994. {
  4995. // Compute the operator before the assignment
  4996. asCTypeInfo lvalue = lctx->type;
  4997. if( lctx->type.isTemporary && !lctx->type.isVariable )
  4998. {
  4999. // The temporary variable must not be freed until the
  5000. // assignment has been performed. lvalue still holds
  5001. // the information about the temporary variable
  5002. lctx->type.isTemporary = false;
  5003. }
  5004. asSExprContext o(engine);
  5005. CompileOperator(opNode, lctx, rctx, &o);
  5006. MergeExprBytecode(rctx, &o);
  5007. rctx->type = o.type;
  5008. // Convert the rvalue to the right type and validate it
  5009. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  5010. MergeExprBytecode(ctx, rctx);
  5011. lctx->type = lvalue;
  5012. // The lvalue continues the same, either it was a variable, or a reference in the register
  5013. }
  5014. else
  5015. {
  5016. // Convert the rvalue to the right type and validate it
  5017. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  5018. MergeExprBytecode(ctx, rctx);
  5019. MergeExprBytecode(ctx, lctx);
  5020. }
  5021. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5022. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5023. ctx->type = lctx->type;
  5024. }
  5025. else if( lctx->type.isExplicitHandle )
  5026. {
  5027. if( !lctx->type.isLValue )
  5028. {
  5029. Error(TXT_NOT_LVALUE, lexpr);
  5030. return -1;
  5031. }
  5032. // Object handles don't have any compound assignment operators
  5033. if( op != ttAssignment )
  5034. {
  5035. asCString str;
  5036. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5037. Error(str.AddressOf(), lexpr);
  5038. return -1;
  5039. }
  5040. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5041. {
  5042. // The object is a value type but that should be treated as a handle
  5043. // TODO: handle: Make sure the right hand value is a handle
  5044. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5045. {
  5046. // An overloaded assignment operator was found (or a compilation error occured)
  5047. return 0;
  5048. }
  5049. // The object must implement the opAssign method
  5050. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  5051. return -1;
  5052. }
  5053. else
  5054. {
  5055. asCDataType dt = lctx->type.dataType;
  5056. dt.MakeReference(false);
  5057. PrepareArgument(&dt, rctx, rexpr, true, 1);
  5058. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5059. {
  5060. asCString str;
  5061. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5062. Error(str.AddressOf(), rexpr);
  5063. return -1;
  5064. }
  5065. MergeExprBytecode(ctx, rctx);
  5066. MergeExprBytecode(ctx, lctx);
  5067. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5068. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5069. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5070. ctx->type = rctx->type;
  5071. }
  5072. }
  5073. else // if( lctx->type.dataType.IsObject() )
  5074. {
  5075. // An ASHANDLE type must not allow a value assignment, as
  5076. // the opAssign operator is used for the handle assignment
  5077. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5078. {
  5079. asCString str;
  5080. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5081. Error(str.AddressOf(), lexpr);
  5082. return -1;
  5083. }
  5084. // The lvalue reference may be marked as a temporary, if for example
  5085. // it was originated as a handle returned from a function. In such
  5086. // cases it must be possible to assign values to it anyway.
  5087. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5088. {
  5089. // Convert the handle to a object reference
  5090. asCDataType to;
  5091. to = lctx->type.dataType;
  5092. to.MakeHandle(false);
  5093. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  5094. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  5095. }
  5096. // Check for overloaded assignment operator
  5097. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5098. {
  5099. // An overloaded assignment operator was found (or a compilation error occured)
  5100. return 0;
  5101. }
  5102. // No registered operator was found. In case the operation is a direct
  5103. // assignment and the rvalue is the same type as the lvalue, then we can
  5104. // still use the byte-for-byte copy to do the assignment
  5105. if( op != ttAssignment )
  5106. {
  5107. asCString str;
  5108. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5109. Error(str.AddressOf(), lexpr);
  5110. return -1;
  5111. }
  5112. // If the left hand expression is simple, i.e. without any
  5113. // function calls or allocations of memory, then we can avoid
  5114. // doing a copy of the right hand expression (done by PrepareArgument).
  5115. // Instead the reference to the value can be placed directly on the
  5116. // stack.
  5117. //
  5118. // This optimization should only be done for value types, where
  5119. // the application developer is responsible for making the
  5120. // implementation safe against unwanted destruction of the input
  5121. // reference before the time.
  5122. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  5123. // Implicitly convert the rvalue to the type of the lvalue
  5124. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5125. simpleExpr = false;
  5126. if( !simpleExpr )
  5127. {
  5128. asCDataType dt = lctx->type.dataType;
  5129. dt.MakeReference(true);
  5130. dt.MakeReadOnly(true);
  5131. PrepareArgument(&dt, rctx, rexpr, true, 1);
  5132. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5133. {
  5134. asCString str;
  5135. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5136. Error(str.AddressOf(), rexpr);
  5137. return -1;
  5138. }
  5139. }
  5140. else
  5141. {
  5142. // Process any property accessor first, before placing the final reference on the stack
  5143. ProcessPropertyGetAccessor(rctx, rexpr);
  5144. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  5145. rctx->bc.Instr(asBC_RDSPtr);
  5146. }
  5147. MergeExprBytecode(ctx, rctx);
  5148. MergeExprBytecode(ctx, lctx);
  5149. if( !simpleExpr )
  5150. {
  5151. if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
  5152. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  5153. // as the value allocated on the stack is guaranteed to be safe.
  5154. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  5155. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  5156. else
  5157. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5158. }
  5159. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5160. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5161. ctx->type = lctx->type;
  5162. }
  5163. return 0;
  5164. }
  5165. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  5166. {
  5167. asCScriptNode *lexpr = expr->firstChild;
  5168. if( lexpr->next )
  5169. {
  5170. // Compile the two expression terms
  5171. asSExprContext lctx(engine), rctx(engine);
  5172. int rr = CompileAssignment(lexpr->next->next, &rctx);
  5173. int lr = CompileCondition(lexpr, &lctx);
  5174. if( lr >= 0 && rr >= 0 )
  5175. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  5176. // Since the operands failed, the assignment was not computed
  5177. ctx->type.SetDummy();
  5178. return -1;
  5179. }
  5180. return CompileCondition(lexpr, ctx);
  5181. }
  5182. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  5183. {
  5184. asCTypeInfo ctype;
  5185. // Compile the conditional expression
  5186. asCScriptNode *cexpr = expr->firstChild;
  5187. if( cexpr->next )
  5188. {
  5189. //-------------------------------
  5190. // Compile the condition
  5191. asSExprContext e(engine);
  5192. int r = CompileExpression(cexpr, &e);
  5193. if( r < 0 )
  5194. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5195. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  5196. {
  5197. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  5198. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5199. }
  5200. ctype = e.type;
  5201. ProcessPropertyGetAccessor(&e, cexpr);
  5202. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  5203. ProcessDeferredParams(&e);
  5204. //-------------------------------
  5205. // Compile the left expression
  5206. asSExprContext le(engine);
  5207. int lr = CompileAssignment(cexpr->next, &le);
  5208. //-------------------------------
  5209. // Compile the right expression
  5210. asSExprContext re(engine);
  5211. int rr = CompileAssignment(cexpr->next->next, &re);
  5212. if( lr >= 0 && rr >= 0 )
  5213. {
  5214. ProcessPropertyGetAccessor(&le, cexpr->next);
  5215. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  5216. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  5217. // Allow a 0 or null in the first case to be implicitly converted to the second type
  5218. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  5219. {
  5220. asCDataType to = re.type.dataType;
  5221. to.MakeReference(false);
  5222. to.MakeReadOnly(true);
  5223. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5224. }
  5225. else if( le.type.IsNullConstant() )
  5226. {
  5227. asCDataType to = re.type.dataType;
  5228. to.MakeHandle(true);
  5229. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5230. }
  5231. //---------------------------------
  5232. // Output the byte code
  5233. int afterLabel = nextLabel++;
  5234. int elseLabel = nextLabel++;
  5235. // If left expression is void, then we don't need to store the result
  5236. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  5237. {
  5238. // Put the code for the condition expression on the output
  5239. MergeExprBytecode(ctx, &e);
  5240. // Added the branch decision
  5241. ctx->type = e.type;
  5242. ConvertToVariable(ctx);
  5243. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5244. ctx->bc.Instr(asBC_ClrHi);
  5245. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5246. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5247. // Add the left expression
  5248. MergeExprBytecode(ctx, &le);
  5249. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5250. // Add the right expression
  5251. ctx->bc.Label((short)elseLabel);
  5252. MergeExprBytecode(ctx, &re);
  5253. ctx->bc.Label((short)afterLabel);
  5254. // Make sure both expressions have the same type
  5255. if( le.type.dataType != re.type.dataType )
  5256. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5257. // Set the type of the result
  5258. ctx->type = le.type;
  5259. }
  5260. else
  5261. {
  5262. // Allocate temporary variable and copy the result to that one
  5263. asCTypeInfo temp;
  5264. temp = le.type;
  5265. temp.dataType.MakeReference(false);
  5266. temp.dataType.MakeReadOnly(false);
  5267. // Make sure the variable isn't used in the initial expression
  5268. int offset = AllocateVariableNotIn(temp.dataType, true, false, &e);
  5269. temp.SetVariable(temp.dataType, offset, true);
  5270. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  5271. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  5272. // Put the code for the condition expression on the output
  5273. MergeExprBytecode(ctx, &e);
  5274. // Add the branch decision
  5275. ctx->type = e.type;
  5276. ConvertToVariable(ctx);
  5277. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5278. ctx->bc.Instr(asBC_ClrHi);
  5279. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5280. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5281. // Assign the result of the left expression to the temporary variable
  5282. asCTypeInfo rtemp;
  5283. rtemp = temp;
  5284. if( rtemp.dataType.IsObjectHandle() )
  5285. rtemp.isExplicitHandle = true;
  5286. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  5287. MergeExprBytecode(ctx, &le);
  5288. if( !rtemp.dataType.IsPrimitive() )
  5289. {
  5290. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5291. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5292. }
  5293. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  5294. if( !rtemp.dataType.IsPrimitive() )
  5295. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5296. // Release the old temporary variable
  5297. ReleaseTemporaryVariable(le.type, &ctx->bc);
  5298. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5299. // Start of the right expression
  5300. ctx->bc.Label((short)elseLabel);
  5301. // Copy the result to the same temporary variable
  5302. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  5303. MergeExprBytecode(ctx, &re);
  5304. if( !rtemp.dataType.IsPrimitive() )
  5305. {
  5306. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5307. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5308. }
  5309. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  5310. if( !rtemp.dataType.IsPrimitive() )
  5311. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5312. // Release the old temporary variable
  5313. ReleaseTemporaryVariable(re.type, &ctx->bc);
  5314. ctx->bc.Label((short)afterLabel);
  5315. // Make sure both expressions have the same type
  5316. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  5317. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5318. // Set the temporary variable as output
  5319. ctx->type = rtemp;
  5320. ctx->type.isExplicitHandle = isExplicitHandle;
  5321. if( !ctx->type.dataType.IsPrimitive() )
  5322. {
  5323. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5324. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  5325. }
  5326. // Make sure the output isn't marked as being a literal constant
  5327. ctx->type.isConstant = false;
  5328. }
  5329. }
  5330. else
  5331. {
  5332. ctx->type.SetDummy();
  5333. return -1;
  5334. }
  5335. }
  5336. else
  5337. return CompileExpression(cexpr, ctx);
  5338. return 0;
  5339. }
  5340. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  5341. {
  5342. asASSERT(expr->nodeType == snExpression);
  5343. // Convert to polish post fix, i.e: a+b => ab+
  5344. // The algorithm that I've implemented here is similar to
  5345. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  5346. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  5347. // Count the nodes in order to preallocate the buffers
  5348. int count = 0;
  5349. asCScriptNode *node = expr->firstChild;
  5350. while( node )
  5351. {
  5352. count++;
  5353. node = node->next;
  5354. }
  5355. asCArray<asCScriptNode *> stack(count);
  5356. asCArray<asCScriptNode *> stack2(count);
  5357. asCArray<asCScriptNode *> postfix(count);
  5358. node = expr->firstChild;
  5359. while( node )
  5360. {
  5361. int precedence = GetPrecedence(node);
  5362. while( stack.GetLength() > 0 &&
  5363. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  5364. stack2.PushLast(stack.PopLast());
  5365. stack.PushLast(node);
  5366. node = node->next;
  5367. }
  5368. while( stack.GetLength() > 0 )
  5369. stack2.PushLast(stack.PopLast());
  5370. // We need to swap operands so that the left
  5371. // operand is always computed before the right
  5372. SwapPostFixOperands(stack2, postfix);
  5373. // Compile the postfix formatted expression
  5374. return CompilePostFixExpression(&postfix, ctx);
  5375. }
  5376. void asCCompiler::SwapPostFixOperands(asCArray<asCScriptNode *> &postfix, asCArray<asCScriptNode *> &target)
  5377. {
  5378. if( postfix.GetLength() == 0 ) return;
  5379. asCScriptNode *node = postfix.PopLast();
  5380. if( node->nodeType == snExprTerm )
  5381. {
  5382. target.PushLast(node);
  5383. return;
  5384. }
  5385. SwapPostFixOperands(postfix, target);
  5386. SwapPostFixOperands(postfix, target);
  5387. target.PushLast(node);
  5388. }
  5389. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  5390. {
  5391. // Shouldn't send any byte code
  5392. asASSERT(ctx->bc.GetLastInstr() == -1);
  5393. // Set the context to a dummy type to avoid further
  5394. // errors in case the expression fails to compile
  5395. ctx->type.SetDummy();
  5396. // Pop the last node
  5397. asCScriptNode *node = postfix->PopLast();
  5398. ctx->exprNode = node;
  5399. // If term, compile the term
  5400. if( node->nodeType == snExprTerm )
  5401. return CompileExpressionTerm(node, ctx);
  5402. // Compile the two expression terms
  5403. asSExprContext r(engine), l(engine);
  5404. int ret;
  5405. ret = CompilePostFixExpression(postfix, &l); if( ret < 0 ) return ret;
  5406. ret = CompilePostFixExpression(postfix, &r); if( ret < 0 ) return ret;
  5407. // Compile the operation
  5408. return CompileOperator(node, &l, &r, ctx);
  5409. }
  5410. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  5411. {
  5412. // Shouldn't send any byte code
  5413. asASSERT(ctx->bc.GetLastInstr() == -1);
  5414. // Set the type as a dummy by default, in case of any compiler errors
  5415. ctx->type.SetDummy();
  5416. // Compile the value node
  5417. asCScriptNode *vnode = node->firstChild;
  5418. while( vnode->nodeType != snExprValue )
  5419. vnode = vnode->next;
  5420. asSExprContext v(engine);
  5421. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  5422. // Compile post fix operators
  5423. asCScriptNode *pnode = vnode->next;
  5424. while( pnode )
  5425. {
  5426. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  5427. pnode = pnode->next;
  5428. }
  5429. // Compile pre fix operators
  5430. pnode = vnode->prev;
  5431. while( pnode )
  5432. {
  5433. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  5434. pnode = pnode->prev;
  5435. }
  5436. // Return the byte code and final type description
  5437. MergeExprBytecodeAndType(ctx, &v);
  5438. return 0;
  5439. }
  5440. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, asCObjectType *objType)
  5441. {
  5442. bool found = false;
  5443. // It is a local variable or parameter?
  5444. // This is not accessible by default arg expressions
  5445. sVariable *v = 0;
  5446. if( !isCompilingDefaultArg && scope == "" && !objType )
  5447. v = variables->GetVariable(name.AddressOf());
  5448. if( v )
  5449. {
  5450. found = true;
  5451. if( v->isPureConstant )
  5452. ctx->type.SetConstantQW(v->type, v->constantValue);
  5453. else if( v->type.IsPrimitive() )
  5454. {
  5455. if( v->type.IsReference() )
  5456. {
  5457. // Copy the reference into the register
  5458. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  5459. ctx->bc.Instr(asBC_PopRPtr);
  5460. ctx->type.Set(v->type);
  5461. }
  5462. else
  5463. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5464. ctx->type.isLValue = true;
  5465. }
  5466. else
  5467. {
  5468. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  5469. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5470. // If the variable is allocated on the heap we have a reference,
  5471. // otherwise the actual object pointer is pushed on the stack.
  5472. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  5473. // Implicitly dereference handle parameters sent by reference
  5474. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  5475. ctx->bc.Instr(asBC_RDSPtr);
  5476. ctx->type.isLValue = true;
  5477. }
  5478. }
  5479. // Is it a class member?
  5480. // This is not accessible by default arg expressions
  5481. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  5482. {
  5483. if( name == THIS_TOKEN && !objType )
  5484. {
  5485. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  5486. // The object pointer is located at stack position 0
  5487. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5488. ctx->type.SetVariable(dt, 0, false);
  5489. ctx->type.dataType.MakeReference(true);
  5490. ctx->type.isLValue = true;
  5491. found = true;
  5492. }
  5493. if( !found )
  5494. {
  5495. // See if there are any matching property accessors
  5496. asSExprContext access(engine);
  5497. if( objType )
  5498. access.type.Set(asCDataType::CreateObject(objType, false));
  5499. else
  5500. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  5501. access.type.dataType.MakeReference(true);
  5502. int r = 0;
  5503. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5504. {
  5505. // This is an index access, check if there is a property accessor that takes an index arg
  5506. asSExprContext dummyArg(engine);
  5507. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, true);
  5508. }
  5509. if( r == 0 )
  5510. {
  5511. // Normal property access
  5512. r = FindPropertyAccessor(name, &access, errNode, true);
  5513. }
  5514. if( r < 0 ) return -1;
  5515. if( access.property_get || access.property_set )
  5516. {
  5517. if( !objType )
  5518. {
  5519. // Prepare the bytecode for the member access
  5520. // This is only done when accessing through the implicit this pointer
  5521. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5522. }
  5523. MergeExprBytecodeAndType(ctx, &access);
  5524. found = true;
  5525. }
  5526. }
  5527. if( !found )
  5528. {
  5529. asCDataType dt;
  5530. if( objType )
  5531. dt = asCDataType::CreateObject(objType, false);
  5532. else
  5533. dt = asCDataType::CreateObject(outFunc->objectType, false);
  5534. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  5535. if( prop )
  5536. {
  5537. if( !objType )
  5538. {
  5539. // The object pointer is located at stack position 0
  5540. // This is only done when accessing through the implicit this pointer
  5541. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5542. ctx->type.SetVariable(dt, 0, false);
  5543. ctx->type.dataType.MakeReference(true);
  5544. Dereference(ctx, true);
  5545. }
  5546. // TODO: This is the same as what is in CompileExpressionPostOp
  5547. // Put the offset on the stack
  5548. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  5549. if( prop->type.IsReference() )
  5550. ctx->bc.Instr(asBC_RDSPtr);
  5551. // Reference to primitive must be stored in the temp register
  5552. if( prop->type.IsPrimitive() )
  5553. {
  5554. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  5555. ctx->bc.Instr(asBC_PopRPtr);
  5556. }
  5557. // Set the new type (keeping info about temp variable)
  5558. ctx->type.dataType = prop->type;
  5559. ctx->type.dataType.MakeReference(true);
  5560. ctx->type.isVariable = false;
  5561. ctx->type.isLValue = true;
  5562. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  5563. {
  5564. // Objects that are members are not references
  5565. ctx->type.dataType.MakeReference(false);
  5566. }
  5567. // If the object reference is const, the property will also be const
  5568. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  5569. found = true;
  5570. }
  5571. }
  5572. }
  5573. // Is it a global property?
  5574. if( !found && !objType )
  5575. {
  5576. // See if there are any matching global property accessors
  5577. // TODO: namespace: Support namespaces for global property accessors too
  5578. asSExprContext access(engine);
  5579. int r = 0;
  5580. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5581. {
  5582. // This is an index access, check if there is a property accessor that takes an index arg
  5583. asSExprContext dummyArg(engine);
  5584. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  5585. }
  5586. if( r == 0 )
  5587. {
  5588. // Normal property access
  5589. r = FindPropertyAccessor(name, &access, errNode);
  5590. }
  5591. if( r < 0 ) return -1;
  5592. if( access.property_get || access.property_set )
  5593. {
  5594. // Prepare the bytecode for the function call
  5595. MergeExprBytecodeAndType(ctx, &access);
  5596. found = true;
  5597. }
  5598. // See if there is any matching global property
  5599. if( !found )
  5600. {
  5601. bool isCompiled = true;
  5602. bool isPureConstant = false;
  5603. bool isAppProp = false;
  5604. asQWORD constantValue;
  5605. asCString ns = scope;
  5606. if( ns == "" )
  5607. {
  5608. if( outFunc->nameSpace != "" )
  5609. ns = outFunc->nameSpace;
  5610. else if( outFunc->objectType && outFunc->objectType->nameSpace != "" )
  5611. ns = outFunc->objectType->nameSpace;
  5612. }
  5613. else if( ns == "::" )
  5614. ns = "";
  5615. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  5616. if( prop )
  5617. {
  5618. found = true;
  5619. // Verify that the global property has been compiled already
  5620. if( isCompiled )
  5621. {
  5622. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5623. {
  5624. ctx->type.dataType.MakeHandle(true);
  5625. ctx->type.isExplicitHandle = true;
  5626. }
  5627. // If the global property is a pure constant
  5628. // we can allow the compiler to optimize it. Pure
  5629. // constants are global constant variables that were
  5630. // initialized by literal constants.
  5631. if( isPureConstant )
  5632. ctx->type.SetConstantQW(prop->type, constantValue);
  5633. else
  5634. {
  5635. // A shared type must not access global vars, unless they
  5636. // too are shared, e.g. application registered vars
  5637. if( outFunc->IsShared() )
  5638. {
  5639. if( !isAppProp )
  5640. {
  5641. asCString str;
  5642. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  5643. Error(str.AddressOf(), errNode);
  5644. // Allow the compilation to continue to catch other problems
  5645. }
  5646. }
  5647. ctx->type.Set(prop->type);
  5648. ctx->type.dataType.MakeReference(true);
  5649. ctx->type.isLValue = true;
  5650. if( ctx->type.dataType.IsPrimitive() )
  5651. {
  5652. // Load the address of the variable into the register
  5653. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  5654. }
  5655. else
  5656. {
  5657. // Push the address of the variable on the stack
  5658. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  5659. // If the object is a value type, then we must validate the existance,
  5660. // as it could potentially be accessed before it is initialized.
  5661. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
  5662. !ctx->type.dataType.IsObjectHandle() )
  5663. {
  5664. // TODO: runtime optimize: This is not necessary for application registered properties
  5665. ctx->bc.Instr(asBC_ChkRefS);
  5666. }
  5667. }
  5668. }
  5669. }
  5670. else
  5671. {
  5672. asCString str;
  5673. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  5674. Error(str.AddressOf(), errNode);
  5675. return -1;
  5676. }
  5677. }
  5678. }
  5679. }
  5680. // Is it the name of a global function?
  5681. if( !noFunction && !found && !objType )
  5682. {
  5683. asCArray<int> funcs;
  5684. asCString ns = scope;
  5685. if( ns == "" )
  5686. {
  5687. if( outFunc->nameSpace != "" )
  5688. ns = outFunc->nameSpace;
  5689. else if( outFunc->objectType && outFunc->objectType->nameSpace != "" )
  5690. ns = outFunc->objectType->nameSpace;
  5691. }
  5692. else if( ns == "::" )
  5693. ns = "";
  5694. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5695. if( funcs.GetLength() > 1 )
  5696. {
  5697. // TODO: funcdef: If multiple functions are found, then the compiler should defer the decision
  5698. // to which one it should use until the value is actually used.
  5699. //
  5700. // - assigning the function pointer to a variable
  5701. // - performing an explicit cast
  5702. // - passing the function pointer to a function as parameter
  5703. asCString str;
  5704. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, name.AddressOf());
  5705. Error(str.AddressOf(), errNode);
  5706. return -1;
  5707. }
  5708. else if( funcs.GetLength() == 1 )
  5709. {
  5710. found = true;
  5711. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  5712. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  5713. outFunc->IsShared() )
  5714. {
  5715. asCString msg;
  5716. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  5717. Error(msg.AddressOf(), errNode);
  5718. return -1;
  5719. }
  5720. // Push the function pointer on the stack
  5721. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  5722. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  5723. }
  5724. }
  5725. // Is it an enum value?
  5726. if( !found && !objType )
  5727. {
  5728. // The enum type may be declared in a namespace too
  5729. asCObjectType *scopeType = 0;
  5730. if( scope != "" && scope != "::" )
  5731. {
  5732. // Use the last scope name as the enum type
  5733. asCString enumType = scope;
  5734. asCString ns;
  5735. int p = scope.FindLast("::");
  5736. if( p != -1 )
  5737. {
  5738. enumType = scope.SubString(p+2);
  5739. ns = scope.SubString(0, p);
  5740. }
  5741. // resolve the type before the scope
  5742. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  5743. }
  5744. asDWORD value = 0;
  5745. asCDataType dt;
  5746. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  5747. {
  5748. // scoped enum value found
  5749. found = true;
  5750. }
  5751. else if( !engine->ep.requireEnumScope )
  5752. {
  5753. // Look for the enum value without explicitly informing the enum type
  5754. asCString ns = scope;
  5755. if( ns == "" )
  5756. {
  5757. // Use implicit scope from the current function that is being compiled
  5758. // TODO: cleanup: This is repeated in a lot of places. Should use function for it
  5759. if( outFunc->nameSpace != "" )
  5760. ns = outFunc->nameSpace;
  5761. else if( outFunc->objectType && outFunc->objectType->nameSpace != "" )
  5762. ns = outFunc->objectType->nameSpace;
  5763. }
  5764. else if( ns == "::" )
  5765. ns = "";
  5766. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  5767. if( e )
  5768. {
  5769. found = true;
  5770. if( e == 2 )
  5771. {
  5772. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  5773. }
  5774. }
  5775. }
  5776. if( found )
  5777. {
  5778. // Even if the enum type is not shared, and we're compiling a shared object,
  5779. // the use of the values are still allowed, since they are treated as constants.
  5780. // an enum value was resolved
  5781. ctx->type.SetConstantDW(dt, value);
  5782. }
  5783. }
  5784. // The name doesn't match any variable
  5785. if( !found )
  5786. {
  5787. // Give dummy value
  5788. ctx->type.SetDummy();
  5789. if( !isOptional )
  5790. {
  5791. // Prepend the scope to the name for the error message
  5792. asCString ename;
  5793. if( scope != "" && scope != "::" )
  5794. ename = scope + "::";
  5795. else
  5796. ename = scope;
  5797. ename += name;
  5798. asCString str;
  5799. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  5800. Error(str.AddressOf(), errNode);
  5801. // Declare the variable now so that it will not be reported again
  5802. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  5803. // Mark the variable as initialized so that the user will not be bother by it again
  5804. sVariable *v = variables->GetVariable(name.AddressOf());
  5805. asASSERT(v);
  5806. if( v ) v->isInitialized = true;
  5807. }
  5808. // Return -1 to signal that the variable wasn't found
  5809. return -1;
  5810. }
  5811. return 0;
  5812. }
  5813. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  5814. {
  5815. // Shouldn't receive any byte code
  5816. asASSERT(ctx->bc.GetLastInstr() == -1);
  5817. asCScriptNode *vnode = node->firstChild;
  5818. ctx->exprNode = vnode;
  5819. if( vnode->nodeType == snVariableAccess )
  5820. {
  5821. // Determine the scope resolution of the variable
  5822. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  5823. // Determine the name of the variable
  5824. asASSERT(vnode->nodeType == snIdentifier );
  5825. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  5826. return CompileVariableAccess(name, scope, ctx, node);
  5827. }
  5828. else if( vnode->nodeType == snConstant )
  5829. {
  5830. if( vnode->tokenType == ttIntConstant )
  5831. {
  5832. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5833. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  5834. // Do we need 64 bits?
  5835. if( val>>32 )
  5836. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5837. else
  5838. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5839. }
  5840. else if( vnode->tokenType == ttBitsConstant )
  5841. {
  5842. asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
  5843. // TODO: Check for overflow
  5844. asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
  5845. // Do we need 64 bits?
  5846. if( val>>32 )
  5847. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5848. else
  5849. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5850. }
  5851. else if( vnode->tokenType == ttFloatConstant )
  5852. {
  5853. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5854. // TODO: Check for overflow
  5855. size_t numScanned;
  5856. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  5857. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  5858. #ifndef AS_USE_DOUBLE_AS_FLOAT
  5859. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  5860. asASSERT(numScanned == vnode->tokenLength - 1);
  5861. #endif
  5862. }
  5863. else if( vnode->tokenType == ttDoubleConstant )
  5864. {
  5865. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5866. // TODO: Check for overflow
  5867. size_t numScanned;
  5868. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  5869. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  5870. asASSERT(numScanned == vnode->tokenLength);
  5871. }
  5872. else if( vnode->tokenType == ttTrue ||
  5873. vnode->tokenType == ttFalse )
  5874. {
  5875. #if AS_SIZEOF_BOOL == 1
  5876. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5877. #else
  5878. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5879. #endif
  5880. }
  5881. else if( vnode->tokenType == ttStringConstant ||
  5882. vnode->tokenType == ttMultilineStringConstant ||
  5883. vnode->tokenType == ttHeredocStringConstant )
  5884. {
  5885. asCString str;
  5886. asCScriptNode *snode = vnode->firstChild;
  5887. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  5888. {
  5889. // Treat the single quoted string as a single character literal
  5890. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5891. asDWORD val = 0;
  5892. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  5893. {
  5894. // This is the start of a UTF8 encoded character. We need to decode it
  5895. val = asStringDecodeUTF8(str.AddressOf(), 0);
  5896. if( val == (asDWORD)-1 )
  5897. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5898. }
  5899. else
  5900. {
  5901. val = ProcessStringConstant(str, snode);
  5902. if( val == (asDWORD)-1 )
  5903. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5904. }
  5905. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  5906. }
  5907. else
  5908. {
  5909. // Process the string constants
  5910. while( snode )
  5911. {
  5912. asCString cat;
  5913. if( snode->tokenType == ttStringConstant )
  5914. {
  5915. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5916. ProcessStringConstant(cat, snode);
  5917. }
  5918. else if( snode->tokenType == ttMultilineStringConstant )
  5919. {
  5920. if( !engine->ep.allowMultilineStrings )
  5921. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  5922. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5923. ProcessStringConstant(cat, snode);
  5924. }
  5925. else if( snode->tokenType == ttHeredocStringConstant )
  5926. {
  5927. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  5928. ProcessHeredocStringConstant(cat, snode);
  5929. }
  5930. str += cat;
  5931. snode = snode->next;
  5932. }
  5933. // Call the string factory function to create a string object
  5934. asCScriptFunction *descr = engine->stringFactory;
  5935. if( descr == 0 )
  5936. {
  5937. // Error
  5938. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  5939. // Give dummy value
  5940. ctx->type.SetDummy();
  5941. return -1;
  5942. }
  5943. else
  5944. {
  5945. // Register the constant string with the engine
  5946. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  5947. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  5948. bool useVariable = false;
  5949. int stackOffset = 0;
  5950. if( descr->DoesReturnOnStack() )
  5951. {
  5952. useVariable = true;
  5953. stackOffset = AllocateVariable(descr->returnType, true);
  5954. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5955. }
  5956. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  5957. }
  5958. }
  5959. }
  5960. else if( vnode->tokenType == ttNull )
  5961. {
  5962. ctx->bc.Instr(asBC_PshNull);
  5963. ctx->type.SetNullConstant();
  5964. }
  5965. else
  5966. asASSERT(false);
  5967. }
  5968. else if( vnode->nodeType == snFunctionCall )
  5969. {
  5970. // Determine the scope resolution
  5971. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  5972. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  5973. }
  5974. else if( vnode->nodeType == snConstructCall )
  5975. {
  5976. CompileConstructCall(vnode, ctx);
  5977. }
  5978. else if( vnode->nodeType == snAssignment )
  5979. {
  5980. asSExprContext e(engine);
  5981. int r = CompileAssignment(vnode, &e);
  5982. if( r < 0 )
  5983. {
  5984. ctx->type.SetDummy();
  5985. return r;
  5986. }
  5987. MergeExprBytecodeAndType(ctx, &e);
  5988. }
  5989. else if( vnode->nodeType == snCast )
  5990. {
  5991. // Implement the cast operator
  5992. CompileConversion(vnode, ctx);
  5993. }
  5994. else
  5995. asASSERT(false);
  5996. return 0;
  5997. }
  5998. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  5999. {
  6000. int charLiteral = -1;
  6001. // Process escape sequences
  6002. asCArray<char> str((int)cstr.GetLength());
  6003. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  6004. {
  6005. #ifdef AS_DOUBLEBYTE_CHARSET
  6006. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  6007. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  6008. {
  6009. // This is the lead character of a double byte character
  6010. // include the trail character without checking it's value.
  6011. str.PushLast(cstr[n]);
  6012. n++;
  6013. str.PushLast(cstr[n]);
  6014. continue;
  6015. }
  6016. #endif
  6017. asUINT val;
  6018. if( processEscapeSequences && cstr[n] == '\\' )
  6019. {
  6020. ++n;
  6021. if( n == cstr.GetLength() )
  6022. {
  6023. if( charLiteral == -1 ) charLiteral = 0;
  6024. return charLiteral;
  6025. }
  6026. // Hexadecimal escape sequences will allow the construction of
  6027. // invalid unicode sequences, but the string should also work as
  6028. // a bytearray so we must support this. The code for working with
  6029. // unicode text must be prepared to handle invalid unicode sequences
  6030. if( cstr[n] == 'x' || cstr[n] == 'X' )
  6031. {
  6032. ++n;
  6033. if( n == cstr.GetLength() ) break;
  6034. val = 0;
  6035. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  6036. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  6037. {
  6038. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6039. val = val*16 + cstr[n] - '0';
  6040. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6041. val = val*16 + cstr[n] - 'a' + 10;
  6042. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6043. val = val*16 + cstr[n] - 'A' + 10;
  6044. else
  6045. break;
  6046. }
  6047. // Rewind one, since the loop will increment it again
  6048. n--;
  6049. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  6050. if( engine->ep.stringEncoding == 0 )
  6051. {
  6052. str.PushLast((asBYTE)val);
  6053. }
  6054. else
  6055. {
  6056. #ifndef AS_BIG_ENDIAN
  6057. str.PushLast((asBYTE)val);
  6058. str.PushLast((asBYTE)(val>>8));
  6059. #else
  6060. str.PushLast((asBYTE)(val>>8));
  6061. str.PushLast((asBYTE)val);
  6062. #endif
  6063. }
  6064. if( charLiteral == -1 ) charLiteral = val;
  6065. continue;
  6066. }
  6067. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  6068. {
  6069. // \u expects 4 hex digits
  6070. // \U expects 8 hex digits
  6071. bool expect2 = cstr[n] == 'u';
  6072. int c = expect2 ? 4 : 8;
  6073. val = 0;
  6074. for( ; c > 0; c-- )
  6075. {
  6076. ++n;
  6077. if( n == cstr.GetLength() ) break;
  6078. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6079. val = val*16 + cstr[n] - '0';
  6080. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6081. val = val*16 + cstr[n] - 'a' + 10;
  6082. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6083. val = val*16 + cstr[n] - 'A' + 10;
  6084. else
  6085. break;
  6086. }
  6087. if( c != 0 )
  6088. {
  6089. // Give warning about invalid code point
  6090. // TODO: Need code position for warning
  6091. asCString msg;
  6092. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  6093. Warning(msg.AddressOf(), node);
  6094. continue;
  6095. }
  6096. }
  6097. else
  6098. {
  6099. if( cstr[n] == '"' )
  6100. val = '"';
  6101. else if( cstr[n] == '\'' )
  6102. val = '\'';
  6103. else if( cstr[n] == 'n' )
  6104. val = '\n';
  6105. else if( cstr[n] == 'r' )
  6106. val = '\r';
  6107. else if( cstr[n] == 't' )
  6108. val = '\t';
  6109. else if( cstr[n] == '0' )
  6110. val = '\0';
  6111. else if( cstr[n] == '\\' )
  6112. val = '\\';
  6113. else
  6114. {
  6115. // Invalid escape sequence
  6116. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  6117. continue;
  6118. }
  6119. }
  6120. }
  6121. else
  6122. {
  6123. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  6124. {
  6125. unsigned int len;
  6126. val = asStringDecodeUTF8(&cstr[n], &len);
  6127. if( val == 0xFFFFFFFF )
  6128. {
  6129. // Incorrect UTF8 encoding. Use only the first byte
  6130. // TODO: Need code position for warning
  6131. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  6132. val = (unsigned char)cstr[n];
  6133. }
  6134. else
  6135. n += len-1;
  6136. }
  6137. else
  6138. val = (unsigned char)cstr[n];
  6139. }
  6140. // Add the character to the final string
  6141. char encodedValue[5];
  6142. int len;
  6143. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  6144. {
  6145. // Convert to UTF8 encoded
  6146. len = asStringEncodeUTF8(val, encodedValue);
  6147. }
  6148. else if( engine->ep.stringEncoding == 1 )
  6149. {
  6150. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  6151. len = asStringEncodeUTF16(val, encodedValue);
  6152. }
  6153. else
  6154. {
  6155. // Do not convert ASCII characters
  6156. encodedValue[0] = (asBYTE)val;
  6157. len = 1;
  6158. }
  6159. if( len < 0 )
  6160. {
  6161. // Give warning about invalid code point
  6162. // TODO: Need code position for warning
  6163. Warning(TXT_INVALID_UNICODE_VALUE, node);
  6164. }
  6165. else
  6166. {
  6167. // Add the encoded value to the final string
  6168. str.Concatenate(encodedValue, len);
  6169. if( charLiteral == -1 ) charLiteral = val;
  6170. }
  6171. }
  6172. cstr.Assign(str.AddressOf(), str.GetLength());
  6173. return charLiteral;
  6174. }
  6175. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  6176. {
  6177. // Remove first line if it only contains whitespace
  6178. int start;
  6179. for( start = 0; start < (int)str.GetLength(); start++ )
  6180. {
  6181. if( str[start] == '\n' )
  6182. {
  6183. // Remove the linebreak as well
  6184. start++;
  6185. break;
  6186. }
  6187. if( str[start] != ' ' &&
  6188. str[start] != '\t' &&
  6189. str[start] != '\r' )
  6190. {
  6191. // Don't remove anything
  6192. start = 0;
  6193. break;
  6194. }
  6195. }
  6196. // Remove last line break and the line after that if it only contains whitespaces
  6197. int end;
  6198. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  6199. {
  6200. if( str[end] == '\n' )
  6201. break;
  6202. if( str[end] != ' ' &&
  6203. str[end] != '\t' &&
  6204. str[end] != '\r' )
  6205. {
  6206. // Don't remove anything
  6207. end = (int)str.GetLength();
  6208. break;
  6209. }
  6210. }
  6211. if( end < 0 ) end = 0;
  6212. asCString tmp;
  6213. if( end > start )
  6214. tmp.Assign(&str[start], end-start);
  6215. ProcessStringConstant(tmp, node, false);
  6216. str = tmp;
  6217. }
  6218. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  6219. {
  6220. asSExprContext expr(engine);
  6221. asCDataType to;
  6222. bool anyErrors = false;
  6223. EImplicitConv convType;
  6224. if( node->nodeType == snConstructCall )
  6225. {
  6226. convType = asIC_EXPLICIT_VAL_CAST;
  6227. // Verify that there is only one argument
  6228. if( node->lastChild->firstChild == 0 ||
  6229. node->lastChild->firstChild != node->lastChild->lastChild )
  6230. {
  6231. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  6232. expr.type.SetDummy();
  6233. anyErrors = true;
  6234. }
  6235. else
  6236. {
  6237. // Compile the expression
  6238. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  6239. if( r < 0 )
  6240. anyErrors = true;
  6241. }
  6242. // Determine the requested type
  6243. // TODO: namespace: Use correct implicit namespace from function
  6244. to = builder->CreateDataTypeFromNode(node->firstChild, script, "");
  6245. to.MakeReadOnly(true); // Default to const
  6246. asASSERT(to.IsPrimitive());
  6247. }
  6248. else
  6249. {
  6250. convType = asIC_EXPLICIT_REF_CAST;
  6251. // Compile the expression
  6252. int r = CompileAssignment(node->lastChild, &expr);
  6253. if( r < 0 )
  6254. anyErrors = true;
  6255. // Determine the requested type
  6256. // TODO: namespace: Use correct implicit namespace from function
  6257. to = builder->CreateDataTypeFromNode(node->firstChild, script, "");
  6258. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  6259. // If the type support object handles, then use it
  6260. if( to.SupportHandles() )
  6261. {
  6262. to.MakeHandle(true);
  6263. }
  6264. else if( !to.IsObjectHandle() )
  6265. {
  6266. // The cast<type> operator can only be used for reference casts
  6267. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  6268. anyErrors = true;
  6269. }
  6270. }
  6271. // Do not allow casting to non shared type if we're compiling a shared method
  6272. if( outFunc->IsShared() &&
  6273. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  6274. {
  6275. asCString msg;
  6276. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  6277. Error(msg.AddressOf(), node);
  6278. anyErrors = true;
  6279. }
  6280. if( anyErrors )
  6281. {
  6282. // Assume that the error can be fixed and allow the compilation to continue
  6283. ctx->type.SetConstantDW(to, 0);
  6284. return;
  6285. }
  6286. ProcessPropertyGetAccessor(&expr, node);
  6287. // We don't want a reference
  6288. if( expr.type.dataType.IsReference() )
  6289. {
  6290. if( expr.type.dataType.IsObject() )
  6291. Dereference(&expr, true);
  6292. else
  6293. ConvertToVariable(&expr);
  6294. }
  6295. ImplicitConversion(&expr, to, node, convType);
  6296. IsVariableInitialized(&expr.type, node);
  6297. // If no type conversion is really tried ignore it
  6298. if( to == expr.type.dataType )
  6299. {
  6300. // This will keep information about constant type
  6301. MergeExprBytecode(ctx, &expr);
  6302. ctx->type = expr.type;
  6303. return;
  6304. }
  6305. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  6306. {
  6307. MergeExprBytecode(ctx, &expr);
  6308. ctx->type = expr.type;
  6309. ctx->type.dataType.MakeReadOnly(true);
  6310. return;
  6311. }
  6312. // The implicit conversion already does most of the conversions permitted,
  6313. // here we'll only treat those conversions that require an explicit cast.
  6314. bool conversionOK = false;
  6315. if( !expr.type.isConstant )
  6316. {
  6317. if( !expr.type.dataType.IsObject() )
  6318. ConvertToTempVariable(&expr);
  6319. if( to.IsObjectHandle() &&
  6320. expr.type.dataType.IsObjectHandle() &&
  6321. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  6322. {
  6323. conversionOK = CompileRefCast(&expr, to, true, node);
  6324. MergeExprBytecode(ctx, &expr);
  6325. ctx->type = expr.type;
  6326. }
  6327. }
  6328. if( conversionOK )
  6329. return;
  6330. // Conversion not available
  6331. ctx->type.SetDummy();
  6332. asCString strTo, strFrom;
  6333. strTo = to.Format();
  6334. strFrom = expr.type.dataType.Format();
  6335. asCString msg;
  6336. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  6337. Error(msg.AddressOf(), node);
  6338. }
  6339. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  6340. {
  6341. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  6342. // Parameters that are sent by reference should be assigned
  6343. // to the evaluated expression if it is an lvalue
  6344. // Evaluate the arguments from last to first
  6345. int n = (int)descr->parameterTypes.GetLength() - 1;
  6346. for( ; n >= 0; n-- )
  6347. {
  6348. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  6349. (descr->parameterTypes[n].IsObject() && deferAll) )
  6350. {
  6351. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  6352. // For &inout, only store the argument if it is for a temporary variable
  6353. if( engine->ep.allowUnsafeReferences ||
  6354. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  6355. {
  6356. // Store the argument for later processing
  6357. asSDeferredParam outParam;
  6358. outParam.argNode = args[n]->exprNode;
  6359. outParam.argType = args[n]->type;
  6360. outParam.argInOutFlags = descr->inOutFlags[n];
  6361. outParam.origExpr = args[n]->origExpr;
  6362. ctx->deferredParams.PushLast(outParam);
  6363. }
  6364. }
  6365. else
  6366. {
  6367. // Release the temporary variable now
  6368. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  6369. }
  6370. // Move the argument's deferred expressions over to the final expression
  6371. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  6372. {
  6373. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  6374. args[n]->deferredParams[m].origExpr = 0;
  6375. }
  6376. args[n]->deferredParams.SetLength(0);
  6377. }
  6378. }
  6379. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  6380. {
  6381. if( isProcessingDeferredParams ) return;
  6382. isProcessingDeferredParams = true;
  6383. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  6384. {
  6385. asSDeferredParam outParam = ctx->deferredParams[n];
  6386. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  6387. {
  6388. // Just release the variable
  6389. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6390. }
  6391. else if( outParam.argInOutFlags == asTM_OUTREF )
  6392. {
  6393. asSExprContext *expr = outParam.origExpr;
  6394. outParam.origExpr = 0;
  6395. if( outParam.argType.dataType.IsObjectHandle() )
  6396. {
  6397. // Implicitly convert the value to a handle
  6398. if( expr->type.dataType.IsObjectHandle() )
  6399. expr->type.isExplicitHandle = true;
  6400. }
  6401. // Verify that the expression result in a lvalue, or a property accessor
  6402. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  6403. {
  6404. asSExprContext rctx(engine);
  6405. rctx.type = outParam.argType;
  6406. if( rctx.type.dataType.IsPrimitive() )
  6407. rctx.type.dataType.MakeReference(false);
  6408. else
  6409. {
  6410. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  6411. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  6412. if( expr->type.isExplicitHandle )
  6413. rctx.type.isExplicitHandle = true;
  6414. }
  6415. asSExprContext o(engine);
  6416. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  6417. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  6418. MergeExprBytecode(ctx, &o);
  6419. }
  6420. else
  6421. {
  6422. // We must still evaluate the expression
  6423. MergeExprBytecode(ctx, expr);
  6424. if( !expr->type.isConstant || expr->type.IsNullConstant() )
  6425. ctx->bc.Instr(asBC_PopPtr);
  6426. // Give a warning, except if the argument is null or 0 which indicate the argument is really to be ignored
  6427. if( !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  6428. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  6429. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6430. }
  6431. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  6432. // Delete the original expression context
  6433. asDELETE(expr,asSExprContext);
  6434. }
  6435. else // &inout
  6436. {
  6437. if( outParam.argType.isTemporary )
  6438. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6439. else if( !outParam.argType.isVariable )
  6440. {
  6441. if( outParam.argType.dataType.IsObject() &&
  6442. ((outParam.argType.dataType.GetBehaviour()->addref &&
  6443. outParam.argType.dataType.GetBehaviour()->release) ||
  6444. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  6445. {
  6446. // Release the object handle that was taken to guarantee the reference
  6447. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6448. }
  6449. }
  6450. }
  6451. }
  6452. ctx->deferredParams.SetLength(0);
  6453. isProcessingDeferredParams = false;
  6454. }
  6455. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  6456. {
  6457. // The first node is a datatype node
  6458. asCString name;
  6459. asCTypeInfo tempObj;
  6460. bool onHeap = true;
  6461. asCArray<int> funcs;
  6462. // It is possible that the name is really a constructor
  6463. asCDataType dt;
  6464. // TODO: namespace: Use correct implicit namespace from function
  6465. dt = builder->CreateDataTypeFromNode(node->firstChild, script, "");
  6466. if( dt.IsPrimitive() )
  6467. {
  6468. // This is a cast to a primitive type
  6469. CompileConversion(node, ctx);
  6470. return;
  6471. }
  6472. // Do not allow constructing non-shared types in shared functions
  6473. if( outFunc->IsShared() &&
  6474. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  6475. {
  6476. asCString msg;
  6477. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  6478. Error(msg.AddressOf(), node);
  6479. }
  6480. // Compile the arguments
  6481. asCArray<asSExprContext *> args;
  6482. asCArray<asCTypeInfo> temporaryVariables;
  6483. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6484. {
  6485. // Check for a value cast behaviour
  6486. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  6487. {
  6488. asSExprContext conv(engine);
  6489. conv.type = args[0]->type;
  6490. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  6491. if( conv.type.dataType.IsEqualExceptRef(dt) )
  6492. {
  6493. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  6494. ctx->bc.AddCode(&args[0]->bc);
  6495. ctx->type = args[0]->type;
  6496. asDELETE(args[0],asSExprContext);
  6497. return;
  6498. }
  6499. }
  6500. // Check for possible constructor/factory
  6501. name = dt.Format();
  6502. asSTypeBehaviour *beh = dt.GetBehaviour();
  6503. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6504. {
  6505. funcs = beh->constructors;
  6506. // Value types and script types are allocated through the constructor
  6507. tempObj.dataType = dt;
  6508. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  6509. tempObj.dataType.MakeReference(true);
  6510. tempObj.isTemporary = true;
  6511. tempObj.isVariable = true;
  6512. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6513. // Push the address of the object on the stack
  6514. if( onHeap )
  6515. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6516. }
  6517. else
  6518. {
  6519. funcs = beh->factories;
  6520. }
  6521. // Special case: Allow calling func(void) with a void expression.
  6522. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6523. {
  6524. // Evaluate the expression before the function call
  6525. MergeExprBytecode(ctx, args[0]);
  6526. asDELETE(args[0],asSExprContext);
  6527. args.SetLength(0);
  6528. }
  6529. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  6530. // If none has been registered, just allocate the variable and push it on the stack.
  6531. if( args.GetLength() == 0 )
  6532. {
  6533. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  6534. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  6535. {
  6536. // Call the default constructor
  6537. ctx->type = tempObj;
  6538. if( onHeap )
  6539. {
  6540. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  6541. ctx->bc.RemoveLastInstr();
  6542. }
  6543. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  6544. // Push the reference on the stack
  6545. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6546. return;
  6547. }
  6548. }
  6549. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  6550. if( funcs.GetLength() != 1 )
  6551. {
  6552. // The error was reported by MatchFunctions()
  6553. // Dummy value
  6554. ctx->type.SetDummy();
  6555. }
  6556. else
  6557. {
  6558. int r = asSUCCESS;
  6559. // Add the default values for arguments not explicitly supplied
  6560. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6561. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6562. r = CompileDefaultArgs(node, args, func);
  6563. if( r == asSUCCESS )
  6564. {
  6565. asCByteCode objBC(engine);
  6566. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6567. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6568. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6569. {
  6570. // If the object is allocated on the stack, then call the constructor as a normal function
  6571. if( onHeap )
  6572. {
  6573. int offset = 0;
  6574. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6575. for( asUINT n = 0; n < args.GetLength(); n++ )
  6576. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6577. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6578. }
  6579. else
  6580. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6581. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  6582. // Add tag that the object has been initialized
  6583. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6584. // The constructor doesn't return anything,
  6585. // so we have to manually inform the type of
  6586. // the return value
  6587. ctx->type = tempObj;
  6588. if( !onHeap )
  6589. ctx->type.dataType.MakeReference(false);
  6590. // Push the address of the object on the stack again
  6591. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6592. }
  6593. else
  6594. {
  6595. // Call the factory to create the reference type
  6596. PerformFunctionCall(funcs[0], ctx, false, &args);
  6597. }
  6598. }
  6599. }
  6600. }
  6601. else
  6602. {
  6603. // Failed to compile the argument list, set the result to the dummy type
  6604. ctx->type.SetDummy();
  6605. }
  6606. // Cleanup
  6607. for( asUINT n = 0; n < args.GetLength(); n++ )
  6608. if( args[n] )
  6609. {
  6610. asDELETE(args[n],asSExprContext);
  6611. }
  6612. }
  6613. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  6614. {
  6615. asCString name;
  6616. asCTypeInfo tempObj;
  6617. asCArray<int> funcs;
  6618. int r = -1;
  6619. asCScriptNode *nm = node->lastChild->prev;
  6620. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  6621. // If we're compiling a class method, then the call may be to a class method
  6622. // even though it looks like an ordinary call to a global function. If it is
  6623. // to a class method it is necessary to implicitly add the this pointer.
  6624. if( objectType == 0 && outFunc && outFunc->objectType && scope != "::" )
  6625. {
  6626. // The special keyword 'super' may be used in constructors to invoke the base
  6627. // class' constructor. This can only be used without any scoping operator
  6628. if( m_isConstructor && name == SUPER_TOKEN && scope == "" )
  6629. {
  6630. // We are calling the base class' constructor, so set the objectType
  6631. objectType = outFunc->objectType;
  6632. }
  6633. else
  6634. {
  6635. // Are there any class methods that may match?
  6636. // TODO: namespace: Should really make sure the scope also match. Because the scope
  6637. // may match a base class, or it may match a global namespace. If it is
  6638. // matching a global scope then we're not calling a class method even
  6639. // if there is a method with the same name.
  6640. asCArray<int> funcs;
  6641. builder->GetObjectMethodDescriptions(name.AddressOf(), outFunc->objectType, funcs, false);
  6642. if( funcs.GetLength() )
  6643. {
  6644. // We're calling a class method, so set the objectType
  6645. objectType = outFunc->objectType;
  6646. }
  6647. }
  6648. // If a class method is being called then implicitly add the this pointer for the call
  6649. if( objectType )
  6650. {
  6651. asCDataType dt = asCDataType::CreateObject(objectType, false);
  6652. // The object pointer is located at stack position 0
  6653. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6654. ctx->type.SetVariable(dt, 0, false);
  6655. ctx->type.dataType.MakeReference(true);
  6656. Dereference(ctx, true);
  6657. }
  6658. }
  6659. // First check for a local variable of a function type
  6660. // Must not allow function names, nor global variables to be returned in this instance
  6661. asSExprContext funcPtr(engine);
  6662. if( objectType == 0 )
  6663. r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  6664. if( r < 0 )
  6665. {
  6666. if( objectType )
  6667. {
  6668. // If we're compiling a constructor and the name of the function is super then
  6669. // the constructor of the base class is being called.
  6670. // super cannot be prefixed with a scope operator
  6671. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  6672. {
  6673. // If the class is not derived from anyone else, calling super should give an error
  6674. if( objectType->derivedFrom )
  6675. funcs = objectType->derivedFrom->beh.constructors;
  6676. // Must not allow calling base class' constructor multiple times
  6677. if( continueLabels.GetLength() > 0 )
  6678. {
  6679. // If a continue label is set we are in a loop
  6680. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  6681. }
  6682. else if( breakLabels.GetLength() > 0 )
  6683. {
  6684. // TODO: inheritance: Should eventually allow constructors in switch statements
  6685. // If a break label is set we are either in a loop or a switch statements
  6686. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  6687. }
  6688. else if( m_isConstructorCalled )
  6689. {
  6690. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  6691. }
  6692. m_isConstructorCalled = true;
  6693. }
  6694. else
  6695. {
  6696. // The scope is can be used to specify the base class
  6697. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType, funcs, objIsConst, scope);
  6698. }
  6699. // It is still possible that there is a class member of a function type
  6700. if( funcs.GetLength() == 0 )
  6701. CompileVariableAccess(name, scope, &funcPtr, node, true, true, objectType);
  6702. }
  6703. else
  6704. {
  6705. // The scope is used to define the namespace
  6706. asCString ns = scope;
  6707. if( ns == "" )
  6708. {
  6709. if( outFunc->nameSpace != "" )
  6710. ns = outFunc->nameSpace;
  6711. else if( outFunc->objectType && outFunc->objectType->nameSpace != "" )
  6712. ns = outFunc->objectType->nameSpace;
  6713. }
  6714. else if( ns == "::" )
  6715. ns = "";
  6716. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  6717. // TODO: funcdef: It is still possible that there is a global variable of a function type
  6718. }
  6719. }
  6720. else if( !funcPtr.type.dataType.GetFuncDef() )
  6721. {
  6722. // The variable is not a function
  6723. asCString msg;
  6724. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  6725. Error(msg.AddressOf(), node);
  6726. return -1;
  6727. }
  6728. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  6729. {
  6730. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  6731. }
  6732. // Compile the arguments
  6733. asCArray<asSExprContext *> args;
  6734. asCArray<asCTypeInfo> temporaryVariables;
  6735. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6736. {
  6737. // Special case: Allow calling func(void) with a void expression.
  6738. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6739. {
  6740. // Evaluate the expression before the function call
  6741. MergeExprBytecode(ctx, args[0]);
  6742. asDELETE(args[0],asSExprContext);
  6743. args.SetLength(0);
  6744. }
  6745. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  6746. if( funcs.GetLength() != 1 )
  6747. {
  6748. // The error was reported by MatchFunctions()
  6749. // Dummy value
  6750. ctx->type.SetDummy();
  6751. }
  6752. else
  6753. {
  6754. int r = asSUCCESS;
  6755. // Add the default values for arguments not explicitly supplied
  6756. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6757. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6758. r = CompileDefaultArgs(node, args, func);
  6759. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  6760. // is it enough to make sure it is in a local variable?
  6761. // For function pointer we must guarantee that the function is safe, i.e.
  6762. // by first storing the function pointer in a local variable (if it isn't already in one)
  6763. if( r == asSUCCESS )
  6764. {
  6765. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6766. {
  6767. if( objectType )
  6768. {
  6769. Dereference(ctx, true); // Dereference the object pointer to access the member
  6770. // The actual function should be called as if a global function
  6771. objectType = 0;
  6772. }
  6773. Dereference(&funcPtr, true);
  6774. ConvertToVariable(&funcPtr);
  6775. ctx->bc.AddCode(&funcPtr.bc);
  6776. if( !funcPtr.type.isTemporary )
  6777. ctx->bc.Instr(asBC_PopPtr);
  6778. }
  6779. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  6780. // If the function pointer was copied to a local variable for the call, then
  6781. // release it again (temporary local variable)
  6782. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6783. {
  6784. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  6785. }
  6786. }
  6787. }
  6788. }
  6789. else
  6790. {
  6791. // Failed to compile the argument list, set the dummy type and continue compilation
  6792. ctx->type.SetDummy();
  6793. }
  6794. // Cleanup
  6795. for( asUINT n = 0; n < args.GetLength(); n++ )
  6796. if( args[n] )
  6797. {
  6798. asDELETE(args[n],asSExprContext);
  6799. }
  6800. return 0;
  6801. }
  6802. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  6803. {
  6804. int op = node->tokenType;
  6805. IsVariableInitialized(&ctx->type, node);
  6806. if( op == ttHandle )
  6807. {
  6808. // Verify that the type allow its handle to be taken
  6809. if( ctx->type.isExplicitHandle ||
  6810. !ctx->type.dataType.IsObject() ||
  6811. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  6812. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  6813. {
  6814. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  6815. return -1;
  6816. }
  6817. // Objects that are not local variables are not references
  6818. // Objects allocated on the stack are also not marked as references
  6819. if( !ctx->type.dataType.IsReference() &&
  6820. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  6821. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  6822. {
  6823. Error(TXT_NOT_VALID_REFERENCE, node);
  6824. return -1;
  6825. }
  6826. // Convert the expression to a handle
  6827. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  6828. {
  6829. asCDataType to = ctx->type.dataType;
  6830. to.MakeHandle(true);
  6831. to.MakeReference(true);
  6832. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  6833. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  6834. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6835. }
  6836. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  6837. {
  6838. // For the ASHANDLE type we'll simply set the expression as a handle
  6839. ctx->type.dataType.MakeHandle(true);
  6840. }
  6841. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  6842. ctx->type.isExplicitHandle = true;
  6843. }
  6844. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6845. {
  6846. // Look for the appropriate method
  6847. // There is no overloadable operator for unary plus
  6848. const char *opName = 0;
  6849. switch( op )
  6850. {
  6851. case ttMinus: opName = "opNeg"; break;
  6852. case ttBitNot: opName = "opCom"; break;
  6853. case ttInc: opName = "opPreInc"; break;
  6854. case ttDec: opName = "opPreDec"; break;
  6855. }
  6856. if( opName )
  6857. {
  6858. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6859. ProcessPropertyGetAccessor(ctx, node);
  6860. // Is it a const value?
  6861. bool isConst = false;
  6862. if( ctx->type.dataType.IsObjectHandle() )
  6863. isConst = ctx->type.dataType.IsHandleToConst();
  6864. else
  6865. isConst = ctx->type.dataType.IsReadOnly();
  6866. // 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
  6867. // Find the correct method
  6868. asCArray<int> funcs;
  6869. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6870. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6871. {
  6872. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6873. if( func->name == opName &&
  6874. func->parameterTypes.GetLength() == 0 &&
  6875. (!isConst || func->isReadOnly) )
  6876. {
  6877. funcs.PushLast(func->id);
  6878. }
  6879. }
  6880. // Did we find the method?
  6881. if( funcs.GetLength() == 1 )
  6882. {
  6883. asCTypeInfo objType = ctx->type;
  6884. asCArray<asSExprContext *> args;
  6885. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6886. ReleaseTemporaryVariable(objType, &ctx->bc);
  6887. return 0;
  6888. }
  6889. else if( funcs.GetLength() == 0 )
  6890. {
  6891. asCString str;
  6892. str = asCString(opName) + "()";
  6893. if( isConst )
  6894. str += " const";
  6895. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6896. Error(str.AddressOf(), node);
  6897. ctx->type.SetDummy();
  6898. return -1;
  6899. }
  6900. else if( funcs.GetLength() > 1 )
  6901. {
  6902. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6903. PrintMatchingFuncs(funcs, node);
  6904. ctx->type.SetDummy();
  6905. return -1;
  6906. }
  6907. }
  6908. else if( op == ttPlus )
  6909. {
  6910. Error(TXT_ILLEGAL_OPERATION, node);
  6911. ctx->type.SetDummy();
  6912. return -1;
  6913. }
  6914. }
  6915. else if( op == ttPlus || op == ttMinus )
  6916. {
  6917. ProcessPropertyGetAccessor(ctx, node);
  6918. asCDataType to = ctx->type.dataType;
  6919. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  6920. if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
  6921. {
  6922. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6923. to = asCDataType::CreatePrimitive(ttInt8, false);
  6924. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6925. to = asCDataType::CreatePrimitive(ttInt16, false);
  6926. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6927. to = asCDataType::CreatePrimitive(ttInt, false);
  6928. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6929. to = asCDataType::CreatePrimitive(ttInt64, false);
  6930. else
  6931. {
  6932. Error(TXT_INVALID_TYPE, node);
  6933. return -1;
  6934. }
  6935. }
  6936. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6937. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6938. if( !ctx->type.isConstant )
  6939. {
  6940. ConvertToTempVariable(ctx);
  6941. asASSERT(!ctx->type.isLValue);
  6942. if( op == ttMinus )
  6943. {
  6944. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6945. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  6946. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6947. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  6948. else if( ctx->type.dataType.IsFloatType() )
  6949. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  6950. else if( ctx->type.dataType.IsDoubleType() )
  6951. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  6952. else
  6953. {
  6954. Error(TXT_ILLEGAL_OPERATION, node);
  6955. return -1;
  6956. }
  6957. return 0;
  6958. }
  6959. }
  6960. else
  6961. {
  6962. if( op == ttMinus )
  6963. {
  6964. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6965. ctx->type.intValue = -ctx->type.intValue;
  6966. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6967. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  6968. else if( ctx->type.dataType.IsFloatType() )
  6969. ctx->type.floatValue = -ctx->type.floatValue;
  6970. else if( ctx->type.dataType.IsDoubleType() )
  6971. ctx->type.doubleValue = -ctx->type.doubleValue;
  6972. else
  6973. {
  6974. Error(TXT_ILLEGAL_OPERATION, node);
  6975. return -1;
  6976. }
  6977. return 0;
  6978. }
  6979. }
  6980. if( op == ttPlus )
  6981. {
  6982. if( !ctx->type.dataType.IsIntegerType() &&
  6983. !ctx->type.dataType.IsFloatType() &&
  6984. !ctx->type.dataType.IsDoubleType() )
  6985. {
  6986. Error(TXT_ILLEGAL_OPERATION, node);
  6987. return -1;
  6988. }
  6989. }
  6990. }
  6991. else if( op == ttNot )
  6992. {
  6993. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6994. {
  6995. if( ctx->type.isConstant )
  6996. {
  6997. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  6998. return 0;
  6999. }
  7000. ProcessPropertyGetAccessor(ctx, node);
  7001. ConvertToTempVariable(ctx);
  7002. asASSERT(!ctx->type.isLValue);
  7003. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7004. }
  7005. else
  7006. {
  7007. Error(TXT_ILLEGAL_OPERATION, node);
  7008. return -1;
  7009. }
  7010. }
  7011. else if( op == ttBitNot )
  7012. {
  7013. ProcessPropertyGetAccessor(ctx, node);
  7014. asCDataType to = ctx->type.dataType;
  7015. if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
  7016. {
  7017. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7018. to = asCDataType::CreatePrimitive(ttUInt8, false);
  7019. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7020. to = asCDataType::CreatePrimitive(ttUInt16, false);
  7021. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7022. to = asCDataType::CreatePrimitive(ttUInt, false);
  7023. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7024. to = asCDataType::CreatePrimitive(ttUInt64, false);
  7025. else
  7026. {
  7027. Error(TXT_INVALID_TYPE, node);
  7028. return -1;
  7029. }
  7030. }
  7031. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7032. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7033. if( ctx->type.dataType.IsUnsignedType() )
  7034. {
  7035. if( ctx->type.isConstant )
  7036. {
  7037. ctx->type.qwordValue = ~ctx->type.qwordValue;
  7038. return 0;
  7039. }
  7040. ConvertToTempVariable(ctx);
  7041. asASSERT(!ctx->type.isLValue);
  7042. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7043. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  7044. else
  7045. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  7046. }
  7047. else
  7048. {
  7049. Error(TXT_ILLEGAL_OPERATION, node);
  7050. return -1;
  7051. }
  7052. }
  7053. else if( op == ttInc || op == ttDec )
  7054. {
  7055. // Need a reference to the primitive that will be updated
  7056. // The result of this expression is the same reference as before
  7057. // Make sure the reference isn't a temporary variable
  7058. if( ctx->type.isTemporary )
  7059. {
  7060. Error(TXT_REF_IS_TEMP, node);
  7061. return -1;
  7062. }
  7063. if( ctx->type.dataType.IsReadOnly() )
  7064. {
  7065. Error(TXT_REF_IS_READ_ONLY, node);
  7066. return -1;
  7067. }
  7068. if( ctx->property_get || ctx->property_set )
  7069. {
  7070. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7071. return -1;
  7072. }
  7073. if( !ctx->type.isLValue )
  7074. {
  7075. Error(TXT_NOT_LVALUE, node);
  7076. return -1;
  7077. }
  7078. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7079. ConvertToReference(ctx);
  7080. else if( !ctx->type.dataType.IsReference() )
  7081. {
  7082. Error(TXT_NOT_VALID_REFERENCE, node);
  7083. return -1;
  7084. }
  7085. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7086. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7087. {
  7088. if( op == ttInc )
  7089. ctx->bc.Instr(asBC_INCi64);
  7090. else
  7091. ctx->bc.Instr(asBC_DECi64);
  7092. }
  7093. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  7094. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  7095. {
  7096. if( op == ttInc )
  7097. ctx->bc.Instr(asBC_INCi);
  7098. else
  7099. ctx->bc.Instr(asBC_DECi);
  7100. }
  7101. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7102. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7103. {
  7104. if( op == ttInc )
  7105. ctx->bc.Instr(asBC_INCi16);
  7106. else
  7107. ctx->bc.Instr(asBC_DECi16);
  7108. }
  7109. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7110. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7111. {
  7112. if( op == ttInc )
  7113. ctx->bc.Instr(asBC_INCi8);
  7114. else
  7115. ctx->bc.Instr(asBC_DECi8);
  7116. }
  7117. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  7118. {
  7119. if( op == ttInc )
  7120. ctx->bc.Instr(asBC_INCf);
  7121. else
  7122. ctx->bc.Instr(asBC_DECf);
  7123. }
  7124. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  7125. {
  7126. if( op == ttInc )
  7127. ctx->bc.Instr(asBC_INCd);
  7128. else
  7129. ctx->bc.Instr(asBC_DECd);
  7130. }
  7131. else
  7132. {
  7133. Error(TXT_ILLEGAL_OPERATION, node);
  7134. return -1;
  7135. }
  7136. }
  7137. else
  7138. {
  7139. // Unknown operator
  7140. asASSERT(false);
  7141. return -1;
  7142. }
  7143. return 0;
  7144. }
  7145. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  7146. {
  7147. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7148. {
  7149. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  7150. ctx->type.dataType.MakeReference(true);
  7151. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  7152. }
  7153. }
  7154. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, bool isThisAccess)
  7155. {
  7156. return FindPropertyAccessor(name, ctx, 0, node, isThisAccess);
  7157. }
  7158. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, bool isThisAccess)
  7159. {
  7160. if( engine->ep.propertyAccessorMode == 0 )
  7161. {
  7162. // Property accessors have been disabled by the application
  7163. return 0;
  7164. }
  7165. int getId = 0, setId = 0;
  7166. asCString getName = "get_" + name;
  7167. asCString setName = "set_" + name;
  7168. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  7169. if( ctx->type.dataType.IsObject() )
  7170. {
  7171. // Check if the object has any methods with the corresponding accessor name(s)
  7172. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7173. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7174. {
  7175. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7176. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7177. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7178. {
  7179. if( getId == 0 )
  7180. getId = ot->methods[n];
  7181. else
  7182. {
  7183. if( multipleGetFuncs.GetLength() == 0 )
  7184. multipleGetFuncs.PushLast(getId);
  7185. multipleGetFuncs.PushLast(ot->methods[n]);
  7186. }
  7187. }
  7188. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7189. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7190. {
  7191. if( setId == 0 )
  7192. setId = ot->methods[n];
  7193. else
  7194. {
  7195. if( multipleSetFuncs.GetLength() == 0 )
  7196. multipleSetFuncs.PushLast(setId);
  7197. multipleSetFuncs.PushLast(ot->methods[n]);
  7198. }
  7199. }
  7200. }
  7201. }
  7202. else
  7203. {
  7204. // Look for appropriate global functions.
  7205. asCArray<int> funcs;
  7206. asUINT n;
  7207. // TODO: namespace: use the proper namespace
  7208. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, "");
  7209. for( n = 0; n < funcs.GetLength(); n++ )
  7210. {
  7211. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7212. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7213. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7214. {
  7215. if( getId == 0 )
  7216. getId = funcs[n];
  7217. else
  7218. {
  7219. if( multipleGetFuncs.GetLength() == 0 )
  7220. multipleGetFuncs.PushLast(getId);
  7221. multipleGetFuncs.PushLast(funcs[n]);
  7222. }
  7223. }
  7224. }
  7225. funcs.SetLength(0);
  7226. // TODO: namespace: use the proper namespace
  7227. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, "");
  7228. for( n = 0; n < funcs.GetLength(); n++ )
  7229. {
  7230. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7231. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7232. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7233. {
  7234. if( setId == 0 )
  7235. setId = funcs[n];
  7236. else
  7237. {
  7238. if( multipleSetFuncs.GetLength() == 0 )
  7239. multipleSetFuncs.PushLast(getId);
  7240. multipleSetFuncs.PushLast(funcs[n]);
  7241. }
  7242. }
  7243. }
  7244. }
  7245. bool isConst = false;
  7246. if( ctx->type.dataType.IsObjectHandle() )
  7247. isConst = ctx->type.dataType.IsHandleToConst();
  7248. else
  7249. isConst = ctx->type.dataType.IsReadOnly();
  7250. // Check for multiple matches
  7251. if( multipleGetFuncs.GetLength() > 0 )
  7252. {
  7253. // Filter the list by constness
  7254. FilterConst(multipleGetFuncs, !isConst);
  7255. if( multipleGetFuncs.GetLength() > 1 )
  7256. {
  7257. asCString str;
  7258. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  7259. Error(str.AddressOf(), node);
  7260. PrintMatchingFuncs(multipleGetFuncs, node);
  7261. return -1;
  7262. }
  7263. else
  7264. {
  7265. // The id may have changed
  7266. getId = multipleGetFuncs[0];
  7267. }
  7268. }
  7269. if( multipleSetFuncs.GetLength() > 0 )
  7270. {
  7271. // Filter the list by constness
  7272. FilterConst(multipleSetFuncs, !isConst);
  7273. if( multipleSetFuncs.GetLength() > 1 )
  7274. {
  7275. asCString str;
  7276. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  7277. Error(str.AddressOf(), node);
  7278. PrintMatchingFuncs(multipleSetFuncs, node);
  7279. return -1;
  7280. }
  7281. else
  7282. {
  7283. // The id may have changed
  7284. setId = multipleSetFuncs[0];
  7285. }
  7286. }
  7287. // Check for type compatibility between get and set accessor
  7288. if( getId && setId )
  7289. {
  7290. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  7291. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  7292. // It is permitted for a getter to return a handle and the setter to take a reference
  7293. int idx = (arg?1:0);
  7294. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  7295. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  7296. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  7297. {
  7298. asCString str;
  7299. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  7300. Error(str.AddressOf(), node);
  7301. asCArray<int> funcs;
  7302. funcs.PushLast(getId);
  7303. funcs.PushLast(setId);
  7304. PrintMatchingFuncs(funcs, node);
  7305. return -1;
  7306. }
  7307. }
  7308. // Check if we are within one of the accessors
  7309. int realGetId = getId;
  7310. int realSetId = setId;
  7311. if( outFunc->objectType && isThisAccess )
  7312. {
  7313. // The property accessors would be virtual functions, so we need to find the real implementation
  7314. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  7315. if( getFunc &&
  7316. getFunc->funcType == asFUNC_VIRTUAL &&
  7317. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  7318. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  7319. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  7320. if( setFunc &&
  7321. setFunc->funcType == asFUNC_VIRTUAL &&
  7322. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  7323. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  7324. }
  7325. // Avoid recursive call, by not treating this as a property accessor call.
  7326. // This will also allow having the real property with the same name as the accessors.
  7327. if( (isThisAccess || outFunc->objectType == 0) &&
  7328. ((realGetId && realGetId == outFunc->id) ||
  7329. (realSetId && realSetId == outFunc->id)) )
  7330. {
  7331. getId = 0;
  7332. setId = 0;
  7333. }
  7334. // Check if the application has disabled script written property accessors
  7335. if( engine->ep.propertyAccessorMode == 1 )
  7336. {
  7337. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  7338. getId = 0;
  7339. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  7340. setId = 0;
  7341. }
  7342. if( getId || setId )
  7343. {
  7344. // Property accessors were found, but we don't know which is to be used yet, so
  7345. // we just prepare the bytecode for the method call, and then store the function ids
  7346. // so that the right one can be used when we get there.
  7347. ctx->property_get = getId;
  7348. ctx->property_set = setId;
  7349. if( ctx->type.dataType.IsObject() )
  7350. {
  7351. // If the object is read-only then we need to remember that
  7352. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  7353. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  7354. ctx->property_const = true;
  7355. else
  7356. ctx->property_const = false;
  7357. // If the object is a handle then we need to remember that
  7358. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  7359. ctx->property_ref = ctx->type.dataType.IsReference();
  7360. }
  7361. // The setter's parameter type is used as the property type,
  7362. // unless only the getter is available
  7363. asCDataType dt;
  7364. if( setId )
  7365. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  7366. else
  7367. dt = builder->GetFunctionDescription(getId)->returnType;
  7368. // Just change the type, the context must still maintain information
  7369. // about previous variable offset and the indicator of temporary variable.
  7370. int offset = ctx->type.stackOffset;
  7371. bool isTemp = ctx->type.isTemporary;
  7372. ctx->type.Set(dt);
  7373. ctx->type.stackOffset = (short)offset;
  7374. ctx->type.isTemporary = isTemp;
  7375. ctx->exprNode = node;
  7376. // Store the argument for later use
  7377. if( arg )
  7378. {
  7379. ctx->property_arg = asNEW(asSExprContext)(engine);
  7380. if( ctx->property_arg == 0 )
  7381. {
  7382. // Out of memory
  7383. return -1;
  7384. }
  7385. MergeExprBytecodeAndType(ctx->property_arg, arg);
  7386. }
  7387. return 1;
  7388. }
  7389. // No accessor was found
  7390. return 0;
  7391. }
  7392. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  7393. {
  7394. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  7395. if( !ctx->property_set )
  7396. {
  7397. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  7398. return -1;
  7399. }
  7400. asCTypeInfo objType = ctx->type;
  7401. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  7402. // Make sure the arg match the property
  7403. asCArray<int> funcs;
  7404. funcs.PushLast(ctx->property_set);
  7405. asCArray<asSExprContext *> args;
  7406. if( ctx->property_arg )
  7407. args.PushLast(ctx->property_arg);
  7408. args.PushLast(arg);
  7409. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7410. if( funcs.GetLength() == 0 )
  7411. {
  7412. // MatchFunctions already reported the error
  7413. if( ctx->property_arg )
  7414. {
  7415. asDELETE(ctx->property_arg, asSExprContext);
  7416. ctx->property_arg = 0;
  7417. }
  7418. return -1;
  7419. }
  7420. if( func->objectType )
  7421. {
  7422. // Setup the context with the original type so the method call gets built correctly
  7423. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7424. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7425. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7426. // Don't allow the call if the object is read-only and the property accessor is not const
  7427. if( ctx->property_const && !func->isReadOnly )
  7428. {
  7429. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7430. asCArray<int> funcs;
  7431. funcs.PushLast(ctx->property_set);
  7432. PrintMatchingFuncs(funcs, node);
  7433. }
  7434. }
  7435. // Call the accessor
  7436. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  7437. if( func->objectType )
  7438. {
  7439. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  7440. if( !objType.isTemporary ||
  7441. !ctx->type.dataType.IsReference() ||
  7442. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7443. {
  7444. // As the method didn't return a reference to a member
  7445. // we can safely release the original object now
  7446. ReleaseTemporaryVariable(objType, &ctx->bc);
  7447. }
  7448. }
  7449. ctx->property_get = 0;
  7450. ctx->property_set = 0;
  7451. if( ctx->property_arg )
  7452. {
  7453. asDELETE(ctx->property_arg, asSExprContext);
  7454. ctx->property_arg = 0;
  7455. }
  7456. return 0;
  7457. }
  7458. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  7459. {
  7460. // If no property accessor has been prepared then don't do anything
  7461. if( !ctx->property_get && !ctx->property_set )
  7462. return;
  7463. if( !ctx->property_get )
  7464. {
  7465. // Raise error on missing accessor
  7466. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  7467. ctx->type.SetDummy();
  7468. return;
  7469. }
  7470. asCTypeInfo objType = ctx->type;
  7471. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  7472. // Make sure the arg match the property
  7473. asCArray<int> funcs;
  7474. funcs.PushLast(ctx->property_get);
  7475. asCArray<asSExprContext *> args;
  7476. if( ctx->property_arg )
  7477. args.PushLast(ctx->property_arg);
  7478. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7479. if( funcs.GetLength() == 0 )
  7480. {
  7481. // MatchFunctions already reported the error
  7482. if( ctx->property_arg )
  7483. {
  7484. asDELETE(ctx->property_arg, asSExprContext);
  7485. ctx->property_arg = 0;
  7486. }
  7487. ctx->type.SetDummy();
  7488. return;
  7489. }
  7490. if( func->objectType )
  7491. {
  7492. // Setup the context with the original type so the method call gets built correctly
  7493. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7494. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7495. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7496. // Don't allow the call if the object is read-only and the property accessor is not const
  7497. if( ctx->property_const && !func->isReadOnly )
  7498. {
  7499. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7500. asCArray<int> funcs;
  7501. funcs.PushLast(ctx->property_get);
  7502. PrintMatchingFuncs(funcs, node);
  7503. }
  7504. }
  7505. // Call the accessor
  7506. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  7507. if( func->objectType )
  7508. {
  7509. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  7510. if( !objType.isTemporary ||
  7511. !ctx->type.dataType.IsReference() ||
  7512. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7513. {
  7514. // As the method didn't return a reference to a member
  7515. // we can safely release the original object now
  7516. ReleaseTemporaryVariable(objType, &ctx->bc);
  7517. }
  7518. }
  7519. ctx->property_get = 0;
  7520. ctx->property_set = 0;
  7521. if( ctx->property_arg )
  7522. {
  7523. asDELETE(ctx->property_arg, asSExprContext);
  7524. ctx->property_arg = 0;
  7525. }
  7526. }
  7527. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  7528. {
  7529. int op = node->tokenType;
  7530. // Check if the variable is initialized (if it indeed is a variable)
  7531. IsVariableInitialized(&ctx->type, node);
  7532. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7533. {
  7534. const char *opName = 0;
  7535. switch( op )
  7536. {
  7537. case ttInc: opName = "opPostInc"; break;
  7538. case ttDec: opName = "opPostDec"; break;
  7539. }
  7540. if( opName )
  7541. {
  7542. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7543. ProcessPropertyGetAccessor(ctx, node);
  7544. // Is it a const value?
  7545. bool isConst = false;
  7546. if( ctx->type.dataType.IsObjectHandle() )
  7547. isConst = ctx->type.dataType.IsHandleToConst();
  7548. else
  7549. isConst = ctx->type.dataType.IsReadOnly();
  7550. // 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
  7551. // Find the correct method
  7552. asCArray<int> funcs;
  7553. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7554. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7555. {
  7556. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7557. if( func->name == opName &&
  7558. func->parameterTypes.GetLength() == 0 &&
  7559. (!isConst || func->isReadOnly) )
  7560. {
  7561. funcs.PushLast(func->id);
  7562. }
  7563. }
  7564. // Did we find the method?
  7565. if( funcs.GetLength() == 1 )
  7566. {
  7567. asCTypeInfo objType = ctx->type;
  7568. asCArray<asSExprContext *> args;
  7569. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7570. ReleaseTemporaryVariable(objType, &ctx->bc);
  7571. return 0;
  7572. }
  7573. else if( funcs.GetLength() == 0 )
  7574. {
  7575. asCString str;
  7576. str = asCString(opName) + "()";
  7577. if( isConst )
  7578. str += " const";
  7579. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7580. Error(str.AddressOf(), node);
  7581. ctx->type.SetDummy();
  7582. return -1;
  7583. }
  7584. else if( funcs.GetLength() > 1 )
  7585. {
  7586. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7587. PrintMatchingFuncs(funcs, node);
  7588. ctx->type.SetDummy();
  7589. return -1;
  7590. }
  7591. }
  7592. }
  7593. else if( op == ttInc || op == ttDec )
  7594. {
  7595. // Make sure the reference isn't a temporary variable
  7596. if( ctx->type.isTemporary )
  7597. {
  7598. Error(TXT_REF_IS_TEMP, node);
  7599. return -1;
  7600. }
  7601. if( ctx->type.dataType.IsReadOnly() )
  7602. {
  7603. Error(TXT_REF_IS_READ_ONLY, node);
  7604. return -1;
  7605. }
  7606. if( ctx->property_get || ctx->property_set )
  7607. {
  7608. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7609. return -1;
  7610. }
  7611. if( !ctx->type.isLValue )
  7612. {
  7613. Error(TXT_NOT_LVALUE, node);
  7614. return -1;
  7615. }
  7616. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7617. ConvertToReference(ctx);
  7618. else if( !ctx->type.dataType.IsReference() )
  7619. {
  7620. Error(TXT_NOT_VALID_REFERENCE, node);
  7621. return -1;
  7622. }
  7623. // Copy the value to a temp before changing it
  7624. ConvertToTempVariable(ctx);
  7625. asASSERT(!ctx->type.isLValue);
  7626. // Increment the value pointed to by the reference still in the register
  7627. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  7628. if( ctx->type.dataType.IsDoubleType() )
  7629. {
  7630. iInc = asBC_INCd;
  7631. iDec = asBC_DECd;
  7632. }
  7633. else if( ctx->type.dataType.IsFloatType() )
  7634. {
  7635. iInc = asBC_INCf;
  7636. iDec = asBC_DECf;
  7637. }
  7638. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  7639. {
  7640. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7641. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7642. {
  7643. iInc = asBC_INCi16;
  7644. iDec = asBC_DECi16;
  7645. }
  7646. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7647. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7648. {
  7649. iInc = asBC_INCi8;
  7650. iDec = asBC_DECi8;
  7651. }
  7652. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7653. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7654. {
  7655. iInc = asBC_INCi64;
  7656. iDec = asBC_DECi64;
  7657. }
  7658. }
  7659. else
  7660. {
  7661. Error(TXT_ILLEGAL_OPERATION, node);
  7662. return -1;
  7663. }
  7664. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  7665. }
  7666. else if( op == ttDot )
  7667. {
  7668. if( node->firstChild->nodeType == snIdentifier )
  7669. {
  7670. ProcessPropertyGetAccessor(ctx, node);
  7671. // Get the property name
  7672. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  7673. // We need to look for get/set property accessors.
  7674. // If found, the context stores information on the get/set accessors
  7675. // until it is known which is to be used.
  7676. int r = 0;
  7677. if( node->next && node->next->tokenType == ttOpenBracket )
  7678. {
  7679. // The property accessor should take an index arg
  7680. asSExprContext dummyArg(engine);
  7681. r = FindPropertyAccessor(name, ctx, &dummyArg, node);
  7682. }
  7683. if( r == 0 )
  7684. r = FindPropertyAccessor(name, ctx, node);
  7685. if( r != 0 )
  7686. return r;
  7687. if( !ctx->type.dataType.IsPrimitive() )
  7688. Dereference(ctx, true);
  7689. if( ctx->type.dataType.IsObjectHandle() )
  7690. {
  7691. // Convert the handle to a normal object
  7692. asCDataType dt = ctx->type.dataType;
  7693. dt.MakeHandle(false);
  7694. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  7695. // The handle may not have been an lvalue, but the dereferenced object is
  7696. ctx->type.isLValue = true;
  7697. }
  7698. // Find the property offset and type
  7699. if( ctx->type.dataType.IsObject() )
  7700. {
  7701. bool isConst = ctx->type.dataType.IsReadOnly();
  7702. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  7703. if( prop )
  7704. {
  7705. // Is the property access allowed?
  7706. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  7707. {
  7708. asCString msg;
  7709. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  7710. Error(msg.AddressOf(), node);
  7711. }
  7712. // Put the offset on the stack
  7713. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  7714. if( prop->type.IsReference() )
  7715. ctx->bc.Instr(asBC_RDSPtr);
  7716. // Reference to primitive must be stored in the temp register
  7717. if( prop->type.IsPrimitive() )
  7718. {
  7719. ctx->bc.Instr(asBC_PopRPtr);
  7720. }
  7721. // Keep information about temporary variables as deferred expression
  7722. if( ctx->type.isTemporary )
  7723. {
  7724. // Add the release of this reference, as a deferred expression
  7725. asSDeferredParam deferred;
  7726. deferred.origExpr = 0;
  7727. deferred.argInOutFlags = asTM_INREF;
  7728. deferred.argNode = 0;
  7729. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  7730. ctx->deferredParams.PushLast(deferred);
  7731. }
  7732. // Set the new type and make sure it is not treated as a variable anymore
  7733. ctx->type.dataType = prop->type;
  7734. ctx->type.dataType.MakeReference(true);
  7735. ctx->type.isVariable = false;
  7736. ctx->type.isTemporary = false;
  7737. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7738. {
  7739. // Objects that are members are not references
  7740. ctx->type.dataType.MakeReference(false);
  7741. }
  7742. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  7743. }
  7744. else
  7745. {
  7746. asCString str;
  7747. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7748. Error(str.AddressOf(), node);
  7749. return -1;
  7750. }
  7751. }
  7752. else
  7753. {
  7754. asCString str;
  7755. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7756. Error(str.AddressOf(), node);
  7757. return -1;
  7758. }
  7759. }
  7760. else
  7761. {
  7762. // Make sure it is an object we are accessing
  7763. if( !ctx->type.dataType.IsObject() )
  7764. {
  7765. asCString str;
  7766. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  7767. Error(str.AddressOf(), node);
  7768. return -1;
  7769. }
  7770. // Process the get property accessor
  7771. ProcessPropertyGetAccessor(ctx, node);
  7772. bool isConst = false;
  7773. if( ctx->type.dataType.IsObjectHandle() )
  7774. isConst = ctx->type.dataType.IsHandleToConst();
  7775. else
  7776. isConst = ctx->type.dataType.IsReadOnly();
  7777. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  7778. asCTypeInfo objType = ctx->type;
  7779. // Compile function call
  7780. int r = CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  7781. if( r < 0 ) return r;
  7782. // If the method returned a reference, then we can't release the original
  7783. // object yet, because the reference may be to a member of it
  7784. if( !objType.isTemporary ||
  7785. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  7786. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7787. {
  7788. // As the method didn't return a reference to a member
  7789. // we can safely release the original object now
  7790. ReleaseTemporaryVariable(objType, &ctx->bc);
  7791. }
  7792. }
  7793. }
  7794. else if( op == ttOpenBracket )
  7795. {
  7796. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  7797. // then we should use that instead of processing it now. If the argument has already been
  7798. // evaluated, then we should process the property accessor as a get access now as the new
  7799. // index operator is on the result of that accessor.
  7800. asCString propertyName;
  7801. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  7802. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  7803. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  7804. {
  7805. // Determine the name of the property accessor
  7806. asCScriptFunction *func = 0;
  7807. if( ctx->property_get )
  7808. func = builder->GetFunctionDescription(ctx->property_get);
  7809. else
  7810. func = builder->GetFunctionDescription(ctx->property_set);
  7811. propertyName = func->GetName();
  7812. propertyName = propertyName.SubString(4);
  7813. // Set the original type of the expression so we can re-evaluate the property accessor
  7814. if( func->objectType )
  7815. {
  7816. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7817. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7818. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7819. }
  7820. else
  7821. {
  7822. ctx->type.SetDummy();
  7823. }
  7824. ctx->property_get = ctx->property_set = 0;
  7825. if( ctx->property_arg )
  7826. {
  7827. asDELETE(ctx->property_arg, asSExprContext);
  7828. ctx->property_arg = 0;
  7829. }
  7830. }
  7831. else
  7832. {
  7833. if( !ctx->type.dataType.IsObject() )
  7834. {
  7835. asCString str;
  7836. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7837. Error(str.AddressOf(), node);
  7838. return -1;
  7839. }
  7840. ProcessPropertyGetAccessor(ctx, node);
  7841. }
  7842. Dereference(ctx, true);
  7843. // Compile the expression
  7844. asSExprContext expr(engine);
  7845. CompileAssignment(node->firstChild, &expr);
  7846. // Check for the existence of the opIndex method
  7847. asSExprContext lctx(engine);
  7848. MergeExprBytecodeAndType(&lctx, ctx);
  7849. int r = 0;
  7850. if( propertyName == "" )
  7851. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  7852. if( r == 0 )
  7853. {
  7854. // Check for accessors methods for the opIndex
  7855. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node);
  7856. if( r == 0 )
  7857. {
  7858. asCString str;
  7859. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7860. Error(str.AddressOf(), node);
  7861. return -1;
  7862. }
  7863. else if( r < 0 )
  7864. return -1;
  7865. MergeExprBytecodeAndType(ctx, &lctx);
  7866. }
  7867. }
  7868. return 0;
  7869. }
  7870. int asCCompiler::GetPrecedence(asCScriptNode *op)
  7871. {
  7872. // x * y, x / y, x % y
  7873. // x + y, x - y
  7874. // x <= y, x < y, x >= y, x > y
  7875. // x = =y, x != y, x xor y, x is y, x !is y
  7876. // x and y
  7877. // x or y
  7878. // The following are not used in this function,
  7879. // but should have lower precedence than the above
  7880. // x ? y : z
  7881. // x = y
  7882. // The expression term have the highest precedence
  7883. if( op->nodeType == snExprTerm )
  7884. return 1;
  7885. // Evaluate operators by token
  7886. int tokenType = op->tokenType;
  7887. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  7888. return 0;
  7889. if( tokenType == ttPlus || tokenType == ttMinus )
  7890. return -1;
  7891. if( tokenType == ttBitShiftLeft ||
  7892. tokenType == ttBitShiftRight ||
  7893. tokenType == ttBitShiftRightArith )
  7894. return -2;
  7895. if( tokenType == ttAmp )
  7896. return -3;
  7897. if( tokenType == ttBitXor )
  7898. return -4;
  7899. if( tokenType == ttBitOr )
  7900. return -5;
  7901. if( tokenType == ttLessThanOrEqual ||
  7902. tokenType == ttLessThan ||
  7903. tokenType == ttGreaterThanOrEqual ||
  7904. tokenType == ttGreaterThan )
  7905. return -6;
  7906. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  7907. return -7;
  7908. if( tokenType == ttAnd )
  7909. return -8;
  7910. if( tokenType == ttOr )
  7911. return -9;
  7912. // Unknown operator
  7913. asASSERT(false);
  7914. return 0;
  7915. }
  7916. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<int> &matches, const asCTypeInfo *argType, int paramNum, bool allowObjectConstruct)
  7917. {
  7918. asUINT bestCost = asUINT(-1);
  7919. matches.SetLength(0);
  7920. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  7921. {
  7922. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  7923. // Does the function have arguments enough?
  7924. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  7925. continue;
  7926. // Can we make the match by implicit conversion?
  7927. asSExprContext ti(engine);
  7928. ti.type = *argType;
  7929. if( argType->dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  7930. asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  7931. // If the function parameter is an inout-reference then it must not be possible to call the
  7932. // function with an incorrect argument type, even though the type can normally be converted.
  7933. if( desc->parameterTypes[paramNum].IsReference() &&
  7934. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  7935. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7936. {
  7937. // Observe, that the below checks are only necessary for when unsafe references have been
  7938. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  7939. // for these value types.
  7940. // Don't allow a primitive to be converted to a reference of another primitive type
  7941. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  7942. desc->parameterTypes[paramNum].GetTokenType() != argType->dataType.GetTokenType() )
  7943. {
  7944. asASSERT( engine->ep.allowUnsafeReferences );
  7945. continue;
  7946. }
  7947. // Don't allow an enum to be converted to a reference of another enum type
  7948. if( desc->parameterTypes[paramNum].IsEnumType() &&
  7949. desc->parameterTypes[paramNum].GetObjectType() != argType->dataType.GetObjectType() )
  7950. {
  7951. asASSERT( engine->ep.allowUnsafeReferences );
  7952. continue;
  7953. }
  7954. // Don't allow a non-handle expression to be converted to a reference to a handle
  7955. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  7956. !argType->dataType.IsObjectHandle() )
  7957. {
  7958. asASSERT( engine->ep.allowUnsafeReferences );
  7959. continue;
  7960. }
  7961. // Don't allow a value type to be converted
  7962. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  7963. (desc->parameterTypes[paramNum].GetObjectType() != argType->dataType.GetObjectType()) )
  7964. {
  7965. asASSERT( engine->ep.allowUnsafeReferences );
  7966. continue;
  7967. }
  7968. }
  7969. // How well does the argument match the function parameter?
  7970. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  7971. {
  7972. if( cost < bestCost )
  7973. {
  7974. matches.SetLength(0);
  7975. bestCost = cost;
  7976. }
  7977. if( cost == bestCost )
  7978. matches.PushLast(funcs[n]);
  7979. }
  7980. }
  7981. return bestCost;
  7982. }
  7983. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  7984. {
  7985. // Reference parameters whose value won't be used don't evaluate the expression
  7986. if( paramType->IsReference() && !(refType & asTM_INREF) )
  7987. {
  7988. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  7989. asSExprContext *orig = asNEW(asSExprContext)(engine);
  7990. if( orig == 0 )
  7991. {
  7992. // Out of memory
  7993. return;
  7994. }
  7995. MergeExprBytecodeAndType(orig, arg);
  7996. arg->origExpr = orig;
  7997. }
  7998. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  7999. // arg still holds the original expression for output parameters
  8000. ctx->bc.AddCode(&arg->bc);
  8001. }
  8002. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8003. {
  8004. ctx->exprNode = node;
  8005. // What type of operator is it?
  8006. int token = node->tokenType;
  8007. if( token == ttUnrecognizedToken )
  8008. {
  8009. // This happens when the compiler is inferring an assignment
  8010. // operation from another action, for example in preparing a value
  8011. // as a function argument
  8012. token = ttAssignment;
  8013. }
  8014. // boolean operators are not overloadable
  8015. if( token == ttAnd ||
  8016. token == ttOr ||
  8017. token == ttXor )
  8018. return false;
  8019. // Dual operators can also be implemented as class methods
  8020. if( token == ttEqual ||
  8021. token == ttNotEqual )
  8022. {
  8023. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8024. // Find the matching opEquals method
  8025. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8026. if( r == 0 )
  8027. {
  8028. // Try again by switching the order of the operands
  8029. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8030. }
  8031. if( r == 1 )
  8032. {
  8033. if( token == ttNotEqual )
  8034. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  8035. // Success, don't continue
  8036. return true;
  8037. }
  8038. else if( r < 0 )
  8039. {
  8040. // Compiler error, don't continue
  8041. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8042. return true;
  8043. }
  8044. }
  8045. if( token == ttEqual ||
  8046. token == ttNotEqual ||
  8047. token == ttLessThan ||
  8048. token == ttLessThanOrEqual ||
  8049. token == ttGreaterThan ||
  8050. token == ttGreaterThanOrEqual )
  8051. {
  8052. bool swappedOrder = false;
  8053. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8054. // Find the matching opCmp method
  8055. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8056. if( r == 0 )
  8057. {
  8058. // Try again by switching the order of the operands
  8059. swappedOrder = true;
  8060. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8061. }
  8062. if( r == 1 )
  8063. {
  8064. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8065. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  8066. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  8067. if( token == ttEqual )
  8068. ctx->bc.Instr(asBC_TZ);
  8069. else if( token == ttNotEqual )
  8070. ctx->bc.Instr(asBC_TNZ);
  8071. else if( (token == ttLessThan && !swappedOrder) ||
  8072. (token == ttGreaterThan && swappedOrder) )
  8073. ctx->bc.Instr(asBC_TS);
  8074. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  8075. (token == ttGreaterThanOrEqual && swappedOrder) )
  8076. ctx->bc.Instr(asBC_TNP);
  8077. else if( (token == ttGreaterThan && !swappedOrder) ||
  8078. (token == ttLessThan && swappedOrder) )
  8079. ctx->bc.Instr(asBC_TP);
  8080. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  8081. (token == ttLessThanOrEqual && swappedOrder) )
  8082. ctx->bc.Instr(asBC_TNS);
  8083. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8084. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  8085. // Success, don't continue
  8086. return true;
  8087. }
  8088. else if( r < 0 )
  8089. {
  8090. // Compiler error, don't continue
  8091. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8092. return true;
  8093. }
  8094. }
  8095. // The rest of the operators are not commutative, and doesn't require specific return type
  8096. const char *op = 0, *op_r = 0;
  8097. switch( token )
  8098. {
  8099. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  8100. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  8101. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  8102. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  8103. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  8104. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  8105. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  8106. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  8107. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  8108. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  8109. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  8110. }
  8111. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  8112. if( op && op_r )
  8113. {
  8114. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8115. // Find the matching operator method
  8116. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  8117. if( r == 0 )
  8118. {
  8119. // Try again by switching the order of the operands, and using the reversed operator
  8120. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  8121. }
  8122. if( r == 1 )
  8123. {
  8124. // Success, don't continue
  8125. return true;
  8126. }
  8127. else if( r < 0 )
  8128. {
  8129. // Compiler error, don't continue
  8130. ctx->type.SetDummy();
  8131. return true;
  8132. }
  8133. }
  8134. // Assignment operators
  8135. op = 0;
  8136. switch( token )
  8137. {
  8138. case ttAssignment: op = "opAssign"; break;
  8139. case ttAddAssign: op = "opAddAssign"; break;
  8140. case ttSubAssign: op = "opSubAssign"; break;
  8141. case ttMulAssign: op = "opMulAssign"; break;
  8142. case ttDivAssign: op = "opDivAssign"; break;
  8143. case ttModAssign: op = "opModAssign"; break;
  8144. case ttOrAssign: op = "opOrAssign"; break;
  8145. case ttAndAssign: op = "opAndAssign"; break;
  8146. case ttXorAssign: op = "opXorAssign"; break;
  8147. case ttShiftLeftAssign: op = "opShlAssign"; break;
  8148. case ttShiftRightLAssign: op = "opShrAssign"; break;
  8149. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  8150. }
  8151. if( op )
  8152. {
  8153. // TODO: Shouldn't accept const lvalue with the assignment operators
  8154. // Find the matching operator method
  8155. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  8156. if( r == 1 )
  8157. {
  8158. // Success, don't continue
  8159. return true;
  8160. }
  8161. else if( r < 0 )
  8162. {
  8163. // Compiler error, don't continue
  8164. ctx->type.SetDummy();
  8165. return true;
  8166. }
  8167. }
  8168. // No suitable operator was found
  8169. return false;
  8170. }
  8171. // Returns negative on compile error
  8172. // zero on no matching operator
  8173. // one on matching operator
  8174. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  8175. {
  8176. // Find the matching method
  8177. if( lctx->type.dataType.IsObject() &&
  8178. (!lctx->type.isExplicitHandle ||
  8179. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  8180. {
  8181. // Is the left value a const?
  8182. bool isConst = false;
  8183. if( lctx->type.dataType.IsObjectHandle() )
  8184. isConst = lctx->type.dataType.IsHandleToConst();
  8185. else
  8186. isConst = lctx->type.dataType.IsReadOnly();
  8187. asCArray<int> funcs;
  8188. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  8189. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8190. {
  8191. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8192. if( func->name == methodName &&
  8193. (!specificReturn || func->returnType == returnType) &&
  8194. func->parameterTypes.GetLength() == 1 &&
  8195. (!isConst || func->isReadOnly) )
  8196. {
  8197. // Make sure the method is accessible by the module
  8198. if( builder->module->accessMask & func->accessMask )
  8199. {
  8200. funcs.PushLast(func->id);
  8201. }
  8202. }
  8203. }
  8204. // Which is the best matching function?
  8205. asCArray<int> ops;
  8206. MatchArgument(funcs, ops, &rctx->type, 0);
  8207. // If the object is not const, then we need to prioritize non-const methods
  8208. if( !isConst )
  8209. FilterConst(ops);
  8210. // Did we find an operator?
  8211. if( ops.GetLength() == 1 )
  8212. {
  8213. // Process the lctx expression as get accessor
  8214. ProcessPropertyGetAccessor(lctx, node);
  8215. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  8216. asCTypeInfo objType = lctx->type;
  8217. asCArray<asSExprContext *> args;
  8218. args.PushLast(rctx);
  8219. MergeExprBytecode(ctx, lctx);
  8220. ctx->type = lctx->type;
  8221. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  8222. // If the method returned a reference, then we can't release the original
  8223. // object yet, because the reference may be to a member of it
  8224. if( !objType.isTemporary ||
  8225. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8226. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  8227. {
  8228. // As the index operator didn't return a reference to a
  8229. // member we can release the original object now
  8230. ReleaseTemporaryVariable(objType, &ctx->bc);
  8231. }
  8232. // Found matching operator
  8233. return 1;
  8234. }
  8235. else if( ops.GetLength() > 1 )
  8236. {
  8237. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8238. PrintMatchingFuncs(ops, node);
  8239. ctx->type.SetDummy();
  8240. // Compiler error
  8241. return -1;
  8242. }
  8243. }
  8244. // No matching operator
  8245. return 0;
  8246. }
  8247. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  8248. {
  8249. if( objectType )
  8250. {
  8251. Dereference(ctx, true);
  8252. // This following warning was removed as there may be valid reasons
  8253. // for calling non-const methods on temporary objects, and we shouldn't
  8254. // warn when there is no way of removing the warning.
  8255. /*
  8256. // Warn if the method is non-const and the object is temporary
  8257. // since the changes will be lost when the object is destroyed.
  8258. // If the object is accessed through a handle, then it is assumed
  8259. // the object is not temporary, even though the handle is.
  8260. if( ctx->type.isTemporary &&
  8261. !ctx->type.dataType.IsObjectHandle() &&
  8262. !engine->scriptFunctions[funcId]->isReadOnly )
  8263. {
  8264. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  8265. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  8266. }
  8267. */ }
  8268. asCByteCode objBC(engine);
  8269. objBC.AddCode(&ctx->bc);
  8270. PrepareFunctionCall(funcId, &ctx->bc, args);
  8271. // Verify if any of the args variable offsets are used in the other code.
  8272. // If they are exchange the offset for a new one
  8273. asUINT n;
  8274. for( n = 0; n < args.GetLength(); n++ )
  8275. {
  8276. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  8277. {
  8278. // Release the current temporary variable
  8279. ReleaseTemporaryVariable(args[n]->type, 0);
  8280. asCDataType dt = args[n]->type.dataType;
  8281. dt.MakeReference(false);
  8282. int l = int(reservedVariables.GetLength());
  8283. objBC.GetVarsUsed(reservedVariables);
  8284. ctx->bc.GetVarsUsed(reservedVariables);
  8285. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  8286. reservedVariables.SetLength(l);
  8287. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  8288. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  8289. args[n]->type.stackOffset = (short)newOffset;
  8290. args[n]->type.isTemporary = true;
  8291. args[n]->type.isVariable = true;
  8292. }
  8293. }
  8294. // If the function will return a value type on the stack, then we must allocate space
  8295. // for that here and push the address on the stack as a hidden argument to the function
  8296. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  8297. if( func->DoesReturnOnStack() )
  8298. {
  8299. asASSERT(!useVariable);
  8300. useVariable = true;
  8301. stackOffset = AllocateVariable(func->returnType, true);
  8302. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  8303. }
  8304. ctx->bc.AddCode(&objBC);
  8305. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  8306. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  8307. }
  8308. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8309. {
  8310. IsVariableInitialized(&lctx->type, node);
  8311. IsVariableInitialized(&rctx->type, node);
  8312. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  8313. node->tokenType == ttIs || node->tokenType == ttNotIs )
  8314. {
  8315. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  8316. return 0;
  8317. }
  8318. else
  8319. {
  8320. // Compile an overloaded operator for the two operands
  8321. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  8322. return 0;
  8323. // If both operands are objects, then we shouldn't continue
  8324. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  8325. {
  8326. asCString str;
  8327. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  8328. Error(str.AddressOf(), node);
  8329. ctx->type.SetDummy();
  8330. return -1;
  8331. }
  8332. // Process the property get accessors (if any)
  8333. ProcessPropertyGetAccessor(lctx, node);
  8334. ProcessPropertyGetAccessor(rctx, node);
  8335. // Make sure we have two variables or constants
  8336. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  8337. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  8338. // Make sure lctx doesn't end up with a variable used in rctx
  8339. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  8340. {
  8341. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  8342. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  8343. ReleaseTemporaryVariable(offset, 0);
  8344. }
  8345. // Math operators
  8346. // + - * / % += -= *= /= %=
  8347. int op = node->tokenType;
  8348. if( op == ttPlus || op == ttAddAssign ||
  8349. op == ttMinus || op == ttSubAssign ||
  8350. op == ttStar || op == ttMulAssign ||
  8351. op == ttSlash || op == ttDivAssign ||
  8352. op == ttPercent || op == ttModAssign )
  8353. {
  8354. CompileMathOperator(node, lctx, rctx, ctx);
  8355. return 0;
  8356. }
  8357. // Bitwise operators
  8358. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  8359. if( op == ttAmp || op == ttAndAssign ||
  8360. op == ttBitOr || op == ttOrAssign ||
  8361. op == ttBitXor || op == ttXorAssign ||
  8362. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8363. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8364. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8365. {
  8366. CompileBitwiseOperator(node, lctx, rctx, ctx);
  8367. return 0;
  8368. }
  8369. // Comparison operators
  8370. // == != < > <= >=
  8371. if( op == ttEqual || op == ttNotEqual ||
  8372. op == ttLessThan || op == ttLessThanOrEqual ||
  8373. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  8374. {
  8375. CompileComparisonOperator(node, lctx, rctx, ctx);
  8376. return 0;
  8377. }
  8378. // Boolean operators
  8379. // && || ^^
  8380. if( op == ttAnd || op == ttOr || op == ttXor )
  8381. {
  8382. CompileBooleanOperator(node, lctx, rctx, ctx);
  8383. return 0;
  8384. }
  8385. }
  8386. asASSERT(false);
  8387. return -1;
  8388. }
  8389. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  8390. {
  8391. int l = int(reservedVariables.GetLength());
  8392. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  8393. ConvertToTempVariable(ctx);
  8394. reservedVariables.SetLength(l);
  8395. }
  8396. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  8397. {
  8398. // This is only used for primitive types and null handles
  8399. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  8400. ConvertToVariable(ctx);
  8401. if( !ctx->type.isTemporary )
  8402. {
  8403. if( ctx->type.dataType.IsPrimitive() )
  8404. {
  8405. // Copy the variable to a temporary variable
  8406. int offset = AllocateVariable(ctx->type.dataType, true);
  8407. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8408. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  8409. else
  8410. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  8411. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8412. }
  8413. else
  8414. {
  8415. // We should never get here
  8416. asASSERT(false);
  8417. }
  8418. }
  8419. }
  8420. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  8421. {
  8422. // We should never get here while the context is still an unprocessed property accessor
  8423. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  8424. int offset;
  8425. if( !ctx->type.isVariable &&
  8426. (ctx->type.dataType.IsObjectHandle() ||
  8427. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  8428. {
  8429. offset = AllocateVariable(ctx->type.dataType, true);
  8430. if( ctx->type.IsNullConstant() )
  8431. {
  8432. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  8433. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  8434. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  8435. }
  8436. else
  8437. {
  8438. // Copy the object handle to a variable
  8439. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  8440. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  8441. ctx->bc.Instr(asBC_PopPtr);
  8442. }
  8443. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8444. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8445. ctx->type.dataType.MakeHandle(true);
  8446. }
  8447. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  8448. ctx->type.dataType.IsPrimitive() )
  8449. {
  8450. if( ctx->type.isConstant )
  8451. {
  8452. offset = AllocateVariable(ctx->type.dataType, true);
  8453. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8454. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  8455. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8456. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  8457. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8458. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  8459. else
  8460. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  8461. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8462. return;
  8463. }
  8464. else
  8465. {
  8466. asASSERT(ctx->type.dataType.IsPrimitive());
  8467. asASSERT(ctx->type.dataType.IsReference());
  8468. ctx->type.dataType.MakeReference(false);
  8469. offset = AllocateVariable(ctx->type.dataType, true);
  8470. // Read the value from the address in the register directly into the variable
  8471. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8472. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  8473. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8474. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  8475. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8476. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  8477. else
  8478. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  8479. }
  8480. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8481. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8482. }
  8483. }
  8484. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  8485. {
  8486. int l = int(reservedVariables.GetLength());
  8487. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  8488. ConvertToVariable(ctx);
  8489. reservedVariables.SetLength(l);
  8490. }
  8491. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8492. {
  8493. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8494. // Implicitly convert the operands to a number type
  8495. asCDataType to;
  8496. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8497. to.SetTokenType(ttDouble);
  8498. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8499. to.SetTokenType(ttFloat);
  8500. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8501. {
  8502. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8503. to.SetTokenType(ttInt64);
  8504. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8505. to.SetTokenType(ttUInt64);
  8506. }
  8507. else
  8508. {
  8509. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8510. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8511. to.SetTokenType(ttInt);
  8512. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8513. to.SetTokenType(ttUInt);
  8514. }
  8515. // If doing an operation with double constant and float variable, the constant should be converted to float
  8516. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8517. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8518. to.SetTokenType(ttFloat);
  8519. // Do the actual conversion
  8520. int l = int(reservedVariables.GetLength());
  8521. rctx->bc.GetVarsUsed(reservedVariables);
  8522. lctx->bc.GetVarsUsed(reservedVariables);
  8523. if( lctx->type.dataType.IsReference() )
  8524. ConvertToVariable(lctx);
  8525. if( rctx->type.dataType.IsReference() )
  8526. ConvertToVariable(rctx);
  8527. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8528. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  8529. reservedVariables.SetLength(l);
  8530. // Verify that the conversion was successful
  8531. if( !lctx->type.dataType.IsIntegerType() &&
  8532. !lctx->type.dataType.IsUnsignedType() &&
  8533. !lctx->type.dataType.IsFloatType() &&
  8534. !lctx->type.dataType.IsDoubleType() )
  8535. {
  8536. asCString str;
  8537. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  8538. Error(str.AddressOf(), node);
  8539. ctx->type.SetDummy();
  8540. return;
  8541. }
  8542. if( !rctx->type.dataType.IsIntegerType() &&
  8543. !rctx->type.dataType.IsUnsignedType() &&
  8544. !rctx->type.dataType.IsFloatType() &&
  8545. !rctx->type.dataType.IsDoubleType() )
  8546. {
  8547. asCString str;
  8548. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  8549. Error(str.AddressOf(), node);
  8550. ctx->type.SetDummy();
  8551. return;
  8552. }
  8553. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8554. // Verify if we are dividing with a constant zero
  8555. int op = node->tokenType;
  8556. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  8557. (op == ttSlash || op == ttDivAssign ||
  8558. op == ttPercent || op == ttModAssign) )
  8559. {
  8560. Error(TXT_DIVIDE_BY_ZERO, node);
  8561. }
  8562. if( !isConstant )
  8563. {
  8564. ConvertToVariableNotIn(lctx, rctx);
  8565. ConvertToVariableNotIn(rctx, lctx);
  8566. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8567. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8568. if( op == ttAddAssign || op == ttSubAssign ||
  8569. op == ttMulAssign || op == ttDivAssign ||
  8570. op == ttModAssign )
  8571. {
  8572. // Merge the operands in the different order so that they are evaluated correctly
  8573. MergeExprBytecode(ctx, rctx);
  8574. MergeExprBytecode(ctx, lctx);
  8575. }
  8576. else
  8577. {
  8578. MergeExprBytecode(ctx, lctx);
  8579. MergeExprBytecode(ctx, rctx);
  8580. }
  8581. ProcessDeferredParams(ctx);
  8582. asEBCInstr instruction = asBC_ADDi;
  8583. if( lctx->type.dataType.IsIntegerType() ||
  8584. lctx->type.dataType.IsUnsignedType() )
  8585. {
  8586. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8587. {
  8588. if( op == ttPlus || op == ttAddAssign )
  8589. instruction = asBC_ADDi;
  8590. else if( op == ttMinus || op == ttSubAssign )
  8591. instruction = asBC_SUBi;
  8592. else if( op == ttStar || op == ttMulAssign )
  8593. instruction = asBC_MULi;
  8594. else if( op == ttSlash || op == ttDivAssign )
  8595. {
  8596. if( lctx->type.dataType.IsIntegerType() )
  8597. instruction = asBC_DIVi;
  8598. else
  8599. instruction = asBC_DIVu;
  8600. }
  8601. else if( op == ttPercent || op == ttModAssign )
  8602. {
  8603. if( lctx->type.dataType.IsIntegerType() )
  8604. instruction = asBC_MODi;
  8605. else
  8606. instruction = asBC_MODu;
  8607. }
  8608. }
  8609. else
  8610. {
  8611. if( op == ttPlus || op == ttAddAssign )
  8612. instruction = asBC_ADDi64;
  8613. else if( op == ttMinus || op == ttSubAssign )
  8614. instruction = asBC_SUBi64;
  8615. else if( op == ttStar || op == ttMulAssign )
  8616. instruction = asBC_MULi64;
  8617. else if( op == ttSlash || op == ttDivAssign )
  8618. {
  8619. if( lctx->type.dataType.IsIntegerType() )
  8620. instruction = asBC_DIVi64;
  8621. else
  8622. instruction = asBC_DIVu64;
  8623. }
  8624. else if( op == ttPercent || op == ttModAssign )
  8625. {
  8626. if( lctx->type.dataType.IsIntegerType() )
  8627. instruction = asBC_MODi64;
  8628. else
  8629. instruction = asBC_MODu64;
  8630. }
  8631. }
  8632. }
  8633. else if( lctx->type.dataType.IsFloatType() )
  8634. {
  8635. if( op == ttPlus || op == ttAddAssign )
  8636. instruction = asBC_ADDf;
  8637. else if( op == ttMinus || op == ttSubAssign )
  8638. instruction = asBC_SUBf;
  8639. else if( op == ttStar || op == ttMulAssign )
  8640. instruction = asBC_MULf;
  8641. else if( op == ttSlash || op == ttDivAssign )
  8642. instruction = asBC_DIVf;
  8643. else if( op == ttPercent || op == ttModAssign )
  8644. instruction = asBC_MODf;
  8645. }
  8646. else if( lctx->type.dataType.IsDoubleType() )
  8647. {
  8648. if( op == ttPlus || op == ttAddAssign )
  8649. instruction = asBC_ADDd;
  8650. else if( op == ttMinus || op == ttSubAssign )
  8651. instruction = asBC_SUBd;
  8652. else if( op == ttStar || op == ttMulAssign )
  8653. instruction = asBC_MULd;
  8654. else if( op == ttSlash || op == ttDivAssign )
  8655. instruction = asBC_DIVd;
  8656. else if( op == ttPercent || op == ttModAssign )
  8657. instruction = asBC_MODd;
  8658. }
  8659. else
  8660. {
  8661. // Shouldn't be possible
  8662. asASSERT(false);
  8663. }
  8664. // Do the operation
  8665. int a = AllocateVariable(lctx->type.dataType, true);
  8666. int b = lctx->type.stackOffset;
  8667. int c = rctx->type.stackOffset;
  8668. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8669. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8670. }
  8671. else
  8672. {
  8673. // Both values are constants
  8674. if( lctx->type.dataType.IsIntegerType() ||
  8675. lctx->type.dataType.IsUnsignedType() )
  8676. {
  8677. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8678. {
  8679. int v = 0;
  8680. if( op == ttPlus )
  8681. v = lctx->type.intValue + rctx->type.intValue;
  8682. else if( op == ttMinus )
  8683. v = lctx->type.intValue - rctx->type.intValue;
  8684. else if( op == ttStar )
  8685. v = lctx->type.intValue * rctx->type.intValue;
  8686. else if( op == ttSlash )
  8687. {
  8688. if( rctx->type.intValue == 0 )
  8689. v = 0;
  8690. else
  8691. if( lctx->type.dataType.IsIntegerType() )
  8692. v = lctx->type.intValue / rctx->type.intValue;
  8693. else
  8694. v = lctx->type.dwordValue / rctx->type.dwordValue;
  8695. }
  8696. else if( op == ttPercent )
  8697. {
  8698. if( rctx->type.intValue == 0 )
  8699. v = 0;
  8700. else
  8701. if( lctx->type.dataType.IsIntegerType() )
  8702. v = lctx->type.intValue % rctx->type.intValue;
  8703. else
  8704. v = lctx->type.dwordValue % rctx->type.dwordValue;
  8705. }
  8706. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8707. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8708. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  8709. ctx->type.dataType.SetTokenType(ttInt);
  8710. }
  8711. else
  8712. {
  8713. asQWORD v = 0;
  8714. if( op == ttPlus )
  8715. v = lctx->type.qwordValue + rctx->type.qwordValue;
  8716. else if( op == ttMinus )
  8717. v = lctx->type.qwordValue - rctx->type.qwordValue;
  8718. else if( op == ttStar )
  8719. v = lctx->type.qwordValue * rctx->type.qwordValue;
  8720. else if( op == ttSlash )
  8721. {
  8722. if( rctx->type.qwordValue == 0 )
  8723. v = 0;
  8724. else
  8725. if( lctx->type.dataType.IsIntegerType() )
  8726. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  8727. else
  8728. v = lctx->type.qwordValue / rctx->type.qwordValue;
  8729. }
  8730. else if( op == ttPercent )
  8731. {
  8732. if( rctx->type.qwordValue == 0 )
  8733. v = 0;
  8734. else
  8735. if( lctx->type.dataType.IsIntegerType() )
  8736. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  8737. else
  8738. v = lctx->type.qwordValue % rctx->type.qwordValue;
  8739. }
  8740. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8741. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8742. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  8743. ctx->type.dataType.SetTokenType(ttInt64);
  8744. }
  8745. }
  8746. else if( lctx->type.dataType.IsFloatType() )
  8747. {
  8748. float v = 0.0f;
  8749. if( op == ttPlus )
  8750. v = lctx->type.floatValue + rctx->type.floatValue;
  8751. else if( op == ttMinus )
  8752. v = lctx->type.floatValue - rctx->type.floatValue;
  8753. else if( op == ttStar )
  8754. v = lctx->type.floatValue * rctx->type.floatValue;
  8755. else if( op == ttSlash )
  8756. {
  8757. if( rctx->type.floatValue == 0 )
  8758. v = 0;
  8759. else
  8760. v = lctx->type.floatValue / rctx->type.floatValue;
  8761. }
  8762. else if( op == ttPercent )
  8763. {
  8764. if( rctx->type.floatValue == 0 )
  8765. v = 0;
  8766. else
  8767. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  8768. }
  8769. ctx->type.SetConstantF(lctx->type.dataType, v);
  8770. }
  8771. else if( lctx->type.dataType.IsDoubleType() )
  8772. {
  8773. double v = 0.0;
  8774. if( op == ttPlus )
  8775. v = lctx->type.doubleValue + rctx->type.doubleValue;
  8776. else if( op == ttMinus )
  8777. v = lctx->type.doubleValue - rctx->type.doubleValue;
  8778. else if( op == ttStar )
  8779. v = lctx->type.doubleValue * rctx->type.doubleValue;
  8780. else if( op == ttSlash )
  8781. {
  8782. if( rctx->type.doubleValue == 0 )
  8783. v = 0;
  8784. else
  8785. v = lctx->type.doubleValue / rctx->type.doubleValue;
  8786. }
  8787. else if( op == ttPercent )
  8788. {
  8789. if( rctx->type.doubleValue == 0 )
  8790. v = 0;
  8791. else
  8792. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  8793. }
  8794. ctx->type.SetConstantD(lctx->type.dataType, v);
  8795. }
  8796. else
  8797. {
  8798. // Shouldn't be possible
  8799. asASSERT(false);
  8800. }
  8801. }
  8802. }
  8803. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8804. {
  8805. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8806. int op = node->tokenType;
  8807. if( op == ttAmp || op == ttAndAssign ||
  8808. op == ttBitOr || op == ttOrAssign ||
  8809. op == ttBitXor || op == ttXorAssign )
  8810. {
  8811. // Convert left hand operand to integer if it's not already one
  8812. asCDataType to;
  8813. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  8814. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8815. to.SetTokenType(ttUInt64);
  8816. else
  8817. to.SetTokenType(ttUInt);
  8818. // Do the actual conversion
  8819. int l = int(reservedVariables.GetLength());
  8820. rctx->bc.GetVarsUsed(reservedVariables);
  8821. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8822. reservedVariables.SetLength(l);
  8823. // Verify that the conversion was successful
  8824. if( !lctx->type.dataType.IsUnsignedType() )
  8825. {
  8826. asCString str;
  8827. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8828. Error(str.AddressOf(), node);
  8829. }
  8830. // Convert right hand operand to same type as left hand operand
  8831. l = int(reservedVariables.GetLength());
  8832. lctx->bc.GetVarsUsed(reservedVariables);
  8833. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true);
  8834. reservedVariables.SetLength(l);
  8835. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  8836. {
  8837. asCString str;
  8838. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  8839. Error(str.AddressOf(), node);
  8840. }
  8841. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8842. if( !isConstant )
  8843. {
  8844. ConvertToVariableNotIn(lctx, rctx);
  8845. ConvertToVariableNotIn(rctx, lctx);
  8846. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8847. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8848. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  8849. {
  8850. // Compound assignments execute the right hand value first
  8851. MergeExprBytecode(ctx, rctx);
  8852. MergeExprBytecode(ctx, lctx);
  8853. }
  8854. else
  8855. {
  8856. MergeExprBytecode(ctx, lctx);
  8857. MergeExprBytecode(ctx, rctx);
  8858. }
  8859. ProcessDeferredParams(ctx);
  8860. asEBCInstr instruction = asBC_BAND;
  8861. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8862. {
  8863. if( op == ttAmp || op == ttAndAssign )
  8864. instruction = asBC_BAND;
  8865. else if( op == ttBitOr || op == ttOrAssign )
  8866. instruction = asBC_BOR;
  8867. else if( op == ttBitXor || op == ttXorAssign )
  8868. instruction = asBC_BXOR;
  8869. }
  8870. else
  8871. {
  8872. if( op == ttAmp || op == ttAndAssign )
  8873. instruction = asBC_BAND64;
  8874. else if( op == ttBitOr || op == ttOrAssign )
  8875. instruction = asBC_BOR64;
  8876. else if( op == ttBitXor || op == ttXorAssign )
  8877. instruction = asBC_BXOR64;
  8878. }
  8879. // Do the operation
  8880. int a = AllocateVariable(lctx->type.dataType, true);
  8881. int b = lctx->type.stackOffset;
  8882. int c = rctx->type.stackOffset;
  8883. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8884. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8885. }
  8886. else
  8887. {
  8888. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8889. {
  8890. asQWORD v = 0;
  8891. if( op == ttAmp )
  8892. v = lctx->type.qwordValue & rctx->type.qwordValue;
  8893. else if( op == ttBitOr )
  8894. v = lctx->type.qwordValue | rctx->type.qwordValue;
  8895. else if( op == ttBitXor )
  8896. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  8897. // Remember the result
  8898. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8899. }
  8900. else
  8901. {
  8902. asDWORD v = 0;
  8903. if( op == ttAmp )
  8904. v = lctx->type.dwordValue & rctx->type.dwordValue;
  8905. else if( op == ttBitOr )
  8906. v = lctx->type.dwordValue | rctx->type.dwordValue;
  8907. else if( op == ttBitXor )
  8908. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  8909. // Remember the result
  8910. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8911. }
  8912. }
  8913. }
  8914. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8915. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8916. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8917. {
  8918. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  8919. if( lctx->type.dataType.IsObject() )
  8920. {
  8921. asCString str;
  8922. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  8923. Error(str.AddressOf(), node);
  8924. // Set an integer value and allow the compiler to continue
  8925. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  8926. return;
  8927. }
  8928. // Convert left hand operand to integer if it's not already one
  8929. asCDataType to = lctx->type.dataType;
  8930. if( lctx->type.dataType.IsUnsignedType() &&
  8931. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  8932. {
  8933. to = asCDataType::CreatePrimitive(ttUInt, false);
  8934. }
  8935. else if( !lctx->type.dataType.IsUnsignedType() )
  8936. {
  8937. asCDataType to;
  8938. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8939. to.SetTokenType(ttInt64);
  8940. else
  8941. to.SetTokenType(ttInt);
  8942. }
  8943. // Do the actual conversion
  8944. int l = int(reservedVariables.GetLength());
  8945. rctx->bc.GetVarsUsed(reservedVariables);
  8946. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8947. reservedVariables.SetLength(l);
  8948. // Verify that the conversion was successful
  8949. if( lctx->type.dataType != to )
  8950. {
  8951. asCString str;
  8952. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8953. Error(str.AddressOf(), node);
  8954. }
  8955. // Right operand must be 32bit uint
  8956. l = int(reservedVariables.GetLength());
  8957. lctx->bc.GetVarsUsed(reservedVariables);
  8958. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  8959. reservedVariables.SetLength(l);
  8960. if( !rctx->type.dataType.IsUnsignedType() )
  8961. {
  8962. asCString str;
  8963. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  8964. Error(str.AddressOf(), node);
  8965. }
  8966. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8967. if( !isConstant )
  8968. {
  8969. ConvertToVariableNotIn(lctx, rctx);
  8970. ConvertToVariableNotIn(rctx, lctx);
  8971. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8972. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8973. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  8974. {
  8975. // Compound assignments execute the right hand value first
  8976. MergeExprBytecode(ctx, rctx);
  8977. MergeExprBytecode(ctx, lctx);
  8978. }
  8979. else
  8980. {
  8981. MergeExprBytecode(ctx, lctx);
  8982. MergeExprBytecode(ctx, rctx);
  8983. }
  8984. ProcessDeferredParams(ctx);
  8985. asEBCInstr instruction = asBC_BSLL;
  8986. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8987. {
  8988. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8989. instruction = asBC_BSLL;
  8990. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8991. instruction = asBC_BSRL;
  8992. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8993. instruction = asBC_BSRA;
  8994. }
  8995. else
  8996. {
  8997. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8998. instruction = asBC_BSLL64;
  8999. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  9000. instruction = asBC_BSRL64;
  9001. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9002. instruction = asBC_BSRA64;
  9003. }
  9004. // Do the operation
  9005. int a = AllocateVariable(lctx->type.dataType, true);
  9006. int b = lctx->type.stackOffset;
  9007. int c = rctx->type.stackOffset;
  9008. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9009. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9010. }
  9011. else
  9012. {
  9013. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9014. {
  9015. asDWORD v = 0;
  9016. if( op == ttBitShiftLeft )
  9017. v = lctx->type.dwordValue << rctx->type.dwordValue;
  9018. else if( op == ttBitShiftRight )
  9019. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  9020. else if( op == ttBitShiftRightArith )
  9021. v = lctx->type.intValue >> rctx->type.dwordValue;
  9022. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9023. }
  9024. else
  9025. {
  9026. asQWORD v = 0;
  9027. if( op == ttBitShiftLeft )
  9028. v = lctx->type.qwordValue << rctx->type.dwordValue;
  9029. else if( op == ttBitShiftRight )
  9030. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  9031. else if( op == ttBitShiftRightArith )
  9032. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  9033. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9034. }
  9035. }
  9036. }
  9037. }
  9038. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9039. {
  9040. // Both operands must be of the same type
  9041. // Implicitly convert the operands to a number type
  9042. asCDataType to;
  9043. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9044. to.SetTokenType(ttDouble);
  9045. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9046. to.SetTokenType(ttFloat);
  9047. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9048. {
  9049. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  9050. to.SetTokenType(ttInt64);
  9051. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9052. to.SetTokenType(ttUInt64);
  9053. }
  9054. else
  9055. {
  9056. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  9057. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  9058. to.SetTokenType(ttInt);
  9059. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9060. to.SetTokenType(ttUInt);
  9061. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  9062. to.SetTokenType(ttBool);
  9063. }
  9064. // If doing an operation with double constant and float variable, the constant should be converted to float
  9065. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  9066. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  9067. to.SetTokenType(ttFloat);
  9068. // Is it an operation on signed values?
  9069. bool signMismatch = false;
  9070. if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
  9071. {
  9072. if( lctx->type.dataType.GetTokenType() == ttUInt64 )
  9073. {
  9074. if( !lctx->type.isConstant )
  9075. signMismatch = true;
  9076. else if( lctx->type.qwordValue & (asQWORD(1)<<63) )
  9077. signMismatch = true;
  9078. }
  9079. if( lctx->type.dataType.GetTokenType() == ttUInt )
  9080. {
  9081. if( !lctx->type.isConstant )
  9082. signMismatch = true;
  9083. else if( lctx->type.dwordValue & (asDWORD(1)<<31) )
  9084. signMismatch = true;
  9085. }
  9086. if( rctx->type.dataType.GetTokenType() == ttUInt64 )
  9087. {
  9088. if( !rctx->type.isConstant )
  9089. signMismatch = true;
  9090. else if( rctx->type.qwordValue & (asQWORD(1)<<63) )
  9091. signMismatch = true;
  9092. }
  9093. if( rctx->type.dataType.GetTokenType() == ttUInt )
  9094. {
  9095. if( !rctx->type.isConstant )
  9096. signMismatch = true;
  9097. else if( rctx->type.dwordValue & (asDWORD(1)<<31) )
  9098. signMismatch = true;
  9099. }
  9100. }
  9101. // Check for signed/unsigned mismatch
  9102. if( signMismatch )
  9103. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  9104. // Do the actual conversion
  9105. int l = int(reservedVariables.GetLength());
  9106. rctx->bc.GetVarsUsed(reservedVariables);
  9107. if( lctx->type.dataType.IsReference() )
  9108. ConvertToVariable(lctx);
  9109. if( rctx->type.dataType.IsReference() )
  9110. ConvertToVariable(rctx);
  9111. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9112. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9113. reservedVariables.SetLength(l);
  9114. // Verify that the conversion was successful
  9115. bool ok = true;
  9116. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  9117. {
  9118. asCString str;
  9119. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9120. Error(str.AddressOf(), node);
  9121. ok = false;
  9122. }
  9123. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  9124. {
  9125. asCString str;
  9126. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9127. Error(str.AddressOf(), node);
  9128. ok = false;
  9129. }
  9130. if( !ok )
  9131. {
  9132. // It wasn't possible to get two valid operands, so we just return
  9133. // a boolean result and let the compiler continue.
  9134. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9135. return;
  9136. }
  9137. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9138. int op = node->tokenType;
  9139. if( !isConstant )
  9140. {
  9141. if( to.IsBooleanType() )
  9142. {
  9143. int op = node->tokenType;
  9144. if( op == ttEqual || op == ttNotEqual )
  9145. {
  9146. // Must convert to temporary variable, because we are changing the value before comparison
  9147. ConvertToTempVariableNotIn(lctx, rctx);
  9148. ConvertToTempVariableNotIn(rctx, lctx);
  9149. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9150. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9151. // Make sure they are equal if not false
  9152. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  9153. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  9154. MergeExprBytecode(ctx, lctx);
  9155. MergeExprBytecode(ctx, rctx);
  9156. ProcessDeferredParams(ctx);
  9157. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  9158. int b = lctx->type.stackOffset;
  9159. int c = rctx->type.stackOffset;
  9160. if( op == ttEqual )
  9161. {
  9162. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  9163. ctx->bc.Instr(asBC_TZ);
  9164. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9165. }
  9166. else if( op == ttNotEqual )
  9167. {
  9168. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  9169. ctx->bc.Instr(asBC_TNZ);
  9170. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9171. }
  9172. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9173. }
  9174. else
  9175. {
  9176. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9177. Error(TXT_ILLEGAL_OPERATION, node);
  9178. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  9179. }
  9180. }
  9181. else
  9182. {
  9183. ConvertToVariableNotIn(lctx, rctx);
  9184. ConvertToVariableNotIn(rctx, lctx);
  9185. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9186. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9187. MergeExprBytecode(ctx, lctx);
  9188. MergeExprBytecode(ctx, rctx);
  9189. ProcessDeferredParams(ctx);
  9190. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  9191. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9192. iCmp = asBC_CMPi;
  9193. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9194. iCmp = asBC_CMPu;
  9195. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9196. iCmp = asBC_CMPi64;
  9197. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9198. iCmp = asBC_CMPu64;
  9199. else if( lctx->type.dataType.IsFloatType() )
  9200. iCmp = asBC_CMPf;
  9201. else if( lctx->type.dataType.IsDoubleType() )
  9202. iCmp = asBC_CMPd;
  9203. else
  9204. asASSERT(false);
  9205. if( op == ttEqual )
  9206. iT = asBC_TZ;
  9207. else if( op == ttNotEqual )
  9208. iT = asBC_TNZ;
  9209. else if( op == ttLessThan )
  9210. iT = asBC_TS;
  9211. else if( op == ttLessThanOrEqual )
  9212. iT = asBC_TNP;
  9213. else if( op == ttGreaterThan )
  9214. iT = asBC_TP;
  9215. else if( op == ttGreaterThanOrEqual )
  9216. iT = asBC_TNS;
  9217. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  9218. int b = lctx->type.stackOffset;
  9219. int c = rctx->type.stackOffset;
  9220. ctx->bc.InstrW_W(iCmp, b, c);
  9221. ctx->bc.Instr(iT);
  9222. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9223. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9224. }
  9225. }
  9226. else
  9227. {
  9228. if( to.IsBooleanType() )
  9229. {
  9230. int op = node->tokenType;
  9231. if( op == ttEqual || op == ttNotEqual )
  9232. {
  9233. // Make sure they are equal if not false
  9234. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9235. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9236. asDWORD v = 0;
  9237. if( op == ttEqual )
  9238. {
  9239. v = lctx->type.intValue - rctx->type.intValue;
  9240. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9241. }
  9242. else if( op == ttNotEqual )
  9243. {
  9244. v = lctx->type.intValue - rctx->type.intValue;
  9245. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9246. }
  9247. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  9248. }
  9249. else
  9250. {
  9251. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9252. Error(TXT_ILLEGAL_OPERATION, node);
  9253. }
  9254. }
  9255. else
  9256. {
  9257. int i = 0;
  9258. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9259. {
  9260. int v = lctx->type.intValue - rctx->type.intValue;
  9261. if( v < 0 ) i = -1;
  9262. if( v > 0 ) i = 1;
  9263. }
  9264. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9265. {
  9266. asDWORD v1 = lctx->type.dwordValue;
  9267. asDWORD v2 = rctx->type.dwordValue;
  9268. if( v1 < v2 ) i = -1;
  9269. if( v1 > v2 ) i = 1;
  9270. }
  9271. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9272. {
  9273. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  9274. if( v < 0 ) i = -1;
  9275. if( v > 0 ) i = 1;
  9276. }
  9277. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9278. {
  9279. asQWORD v1 = lctx->type.qwordValue;
  9280. asQWORD v2 = rctx->type.qwordValue;
  9281. if( v1 < v2 ) i = -1;
  9282. if( v1 > v2 ) i = 1;
  9283. }
  9284. else if( lctx->type.dataType.IsFloatType() )
  9285. {
  9286. float v = lctx->type.floatValue - rctx->type.floatValue;
  9287. if( v < 0 ) i = -1;
  9288. if( v > 0 ) i = 1;
  9289. }
  9290. else if( lctx->type.dataType.IsDoubleType() )
  9291. {
  9292. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  9293. if( v < 0 ) i = -1;
  9294. if( v > 0 ) i = 1;
  9295. }
  9296. if( op == ttEqual )
  9297. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9298. else if( op == ttNotEqual )
  9299. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9300. else if( op == ttLessThan )
  9301. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9302. else if( op == ttLessThanOrEqual )
  9303. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9304. else if( op == ttGreaterThan )
  9305. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9306. else if( op == ttGreaterThanOrEqual )
  9307. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9308. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  9309. }
  9310. }
  9311. }
  9312. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  9313. {
  9314. // Put the result on the stack
  9315. if( asReference )
  9316. {
  9317. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  9318. ctx->type.dataType.MakeReference(true);
  9319. }
  9320. else
  9321. {
  9322. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9323. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  9324. else
  9325. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  9326. }
  9327. }
  9328. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9329. {
  9330. // Both operands must be booleans
  9331. asCDataType to;
  9332. to.SetTokenType(ttBool);
  9333. // Do the actual conversion
  9334. int l = int(reservedVariables.GetLength());
  9335. rctx->bc.GetVarsUsed(reservedVariables);
  9336. lctx->bc.GetVarsUsed(reservedVariables);
  9337. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9338. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9339. reservedVariables.SetLength(l);
  9340. // Verify that the conversion was successful
  9341. if( !lctx->type.dataType.IsBooleanType() )
  9342. {
  9343. asCString str;
  9344. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  9345. Error(str.AddressOf(), node);
  9346. // Force the conversion to allow compilation to proceed
  9347. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  9348. }
  9349. if( !rctx->type.dataType.IsBooleanType() )
  9350. {
  9351. asCString str;
  9352. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  9353. Error(str.AddressOf(), node);
  9354. // Force the conversion to allow compilation to proceed
  9355. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  9356. }
  9357. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9358. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  9359. // What kind of operator is it?
  9360. int op = node->tokenType;
  9361. if( op == ttXor )
  9362. {
  9363. if( !isConstant )
  9364. {
  9365. // Must convert to temporary variable, because we are changing the value before comparison
  9366. ConvertToTempVariableNotIn(lctx, rctx);
  9367. ConvertToTempVariableNotIn(rctx, lctx);
  9368. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9369. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9370. // Make sure they are equal if not false
  9371. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  9372. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  9373. MergeExprBytecode(ctx, lctx);
  9374. MergeExprBytecode(ctx, rctx);
  9375. ProcessDeferredParams(ctx);
  9376. int a = AllocateVariable(ctx->type.dataType, true);
  9377. int b = lctx->type.stackOffset;
  9378. int c = rctx->type.stackOffset;
  9379. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  9380. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9381. }
  9382. else
  9383. {
  9384. // Make sure they are equal if not false
  9385. #if AS_SIZEOF_BOOL == 1
  9386. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  9387. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  9388. asBYTE v = 0;
  9389. v = lctx->type.byteValue - rctx->type.byteValue;
  9390. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9391. ctx->type.isConstant = true;
  9392. ctx->type.byteValue = v;
  9393. #else
  9394. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9395. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9396. asDWORD v = 0;
  9397. v = lctx->type.intValue - rctx->type.intValue;
  9398. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9399. ctx->type.isConstant = true;
  9400. ctx->type.dwordValue = v;
  9401. #endif
  9402. }
  9403. }
  9404. else if( op == ttAnd ||
  9405. op == ttOr )
  9406. {
  9407. if( !isConstant )
  9408. {
  9409. // If or-operator and first value is 1 the second value shouldn't be calculated
  9410. // if and-operator and first value is 0 the second value shouldn't be calculated
  9411. ConvertToVariable(lctx);
  9412. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9413. MergeExprBytecode(ctx, lctx);
  9414. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  9415. int label1 = nextLabel++;
  9416. int label2 = nextLabel++;
  9417. if( op == ttAnd )
  9418. {
  9419. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9420. ctx->bc.Instr(asBC_ClrHi);
  9421. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  9422. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  9423. ctx->bc.InstrINT(asBC_JMP, label2);
  9424. }
  9425. else if( op == ttOr )
  9426. {
  9427. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9428. ctx->bc.Instr(asBC_ClrHi);
  9429. ctx->bc.InstrDWORD(asBC_JZ, label1);
  9430. #if AS_SIZEOF_BOOL == 1
  9431. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9432. #else
  9433. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9434. #endif
  9435. ctx->bc.InstrINT(asBC_JMP, label2);
  9436. }
  9437. ctx->bc.Label((short)label1);
  9438. ConvertToVariable(rctx);
  9439. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9440. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  9441. MergeExprBytecode(ctx, rctx);
  9442. ctx->bc.Label((short)label2);
  9443. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  9444. }
  9445. else
  9446. {
  9447. #if AS_SIZEOF_BOOL == 1
  9448. asBYTE v = 0;
  9449. if( op == ttAnd )
  9450. v = lctx->type.byteValue && rctx->type.byteValue;
  9451. else if( op == ttOr )
  9452. v = lctx->type.byteValue || rctx->type.byteValue;
  9453. // Remember the result
  9454. ctx->type.isConstant = true;
  9455. ctx->type.byteValue = v;
  9456. #else
  9457. asDWORD v = 0;
  9458. if( op == ttAnd )
  9459. v = lctx->type.dwordValue && rctx->type.dwordValue;
  9460. else if( op == ttOr )
  9461. v = lctx->type.dwordValue || rctx->type.dwordValue;
  9462. // Remember the result
  9463. ctx->type.isConstant = true;
  9464. ctx->type.dwordValue = v;
  9465. #endif
  9466. }
  9467. }
  9468. }
  9469. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9470. {
  9471. // Process the property accessor as get
  9472. ProcessPropertyGetAccessor(lctx, node);
  9473. ProcessPropertyGetAccessor(rctx, node);
  9474. // Make sure lctx doesn't end up with a variable used in rctx
  9475. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9476. {
  9477. asCArray<int> vars;
  9478. rctx->bc.GetVarsUsed(vars);
  9479. int offset = AllocateVariable(lctx->type.dataType, true);
  9480. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9481. ReleaseTemporaryVariable(offset, 0);
  9482. }
  9483. // Warn if not both operands are explicit handles
  9484. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  9485. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  9486. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  9487. {
  9488. Warning(TXT_HANDLE_COMPARISON, node);
  9489. }
  9490. // If one of the operands is a value type used as handle, we should look for the opEquals method
  9491. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  9492. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  9493. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  9494. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  9495. {
  9496. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9497. // Find the matching opEquals method
  9498. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9499. if( r == 0 )
  9500. {
  9501. // Try again by switching the order of the operands
  9502. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9503. }
  9504. if( r == 1 )
  9505. {
  9506. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  9507. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9508. // Success, don't continue
  9509. return;
  9510. }
  9511. else if( r == 0 )
  9512. {
  9513. // Couldn't find opEquals method
  9514. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  9515. }
  9516. // Compiler error, don't continue
  9517. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9518. return;
  9519. }
  9520. // Implicitly convert null to the other type
  9521. asCDataType to;
  9522. if( lctx->type.IsNullConstant() )
  9523. to = rctx->type.dataType;
  9524. else if( rctx->type.IsNullConstant() )
  9525. to = lctx->type.dataType;
  9526. else
  9527. {
  9528. // TODO: Use the common base type
  9529. to = lctx->type.dataType;
  9530. }
  9531. // Need to pop the value if it is a null constant
  9532. if( lctx->type.IsNullConstant() )
  9533. lctx->bc.Instr(asBC_PopPtr);
  9534. if( rctx->type.IsNullConstant() )
  9535. rctx->bc.Instr(asBC_PopPtr);
  9536. // Convert both sides to explicit handles
  9537. to.MakeHandle(true);
  9538. to.MakeReference(false);
  9539. if( !to.IsObjectHandle() )
  9540. {
  9541. // Compiler error, don't continue
  9542. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  9543. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9544. return;
  9545. }
  9546. // Do the conversion
  9547. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9548. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9549. // Both operands must be of the same type
  9550. // Verify that the conversion was successful
  9551. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  9552. {
  9553. asCString str;
  9554. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9555. Error(str.AddressOf(), node);
  9556. }
  9557. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  9558. {
  9559. asCString str;
  9560. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9561. Error(str.AddressOf(), node);
  9562. }
  9563. // Make sure it really is handles that are being compared
  9564. if( !lctx->type.dataType.IsObjectHandle() )
  9565. {
  9566. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  9567. }
  9568. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  9569. int op = node->tokenType;
  9570. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  9571. {
  9572. // If the object handle already is in a variable we must manually pop it from the stack
  9573. if( lctx->type.isVariable )
  9574. lctx->bc.Instr(asBC_PopPtr);
  9575. if( rctx->type.isVariable )
  9576. rctx->bc.Instr(asBC_PopPtr);
  9577. // TODO: runtime optimize: don't do REFCPY
  9578. ConvertToVariableNotIn(lctx, rctx);
  9579. ConvertToVariable(rctx);
  9580. MergeExprBytecode(ctx, lctx);
  9581. MergeExprBytecode(ctx, rctx);
  9582. int a = AllocateVariable(ctx->type.dataType, true);
  9583. int b = lctx->type.stackOffset;
  9584. int c = rctx->type.stackOffset;
  9585. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  9586. if( op == ttEqual || op == ttIs )
  9587. ctx->bc.Instr(asBC_TZ);
  9588. else if( op == ttNotEqual || op == ttNotIs )
  9589. ctx->bc.Instr(asBC_TNZ);
  9590. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9591. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9592. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  9593. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  9594. ProcessDeferredParams(ctx);
  9595. }
  9596. else
  9597. {
  9598. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9599. Error(TXT_ILLEGAL_OPERATION, node);
  9600. }
  9601. }
  9602. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  9603. {
  9604. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  9605. // A shared object may not call non-shared functions
  9606. if( outFunc->IsShared() && !descr->IsShared() )
  9607. {
  9608. asCString msg;
  9609. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  9610. Error(msg.AddressOf(), ctx->exprNode);
  9611. }
  9612. // Check if the function is private
  9613. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  9614. {
  9615. asCString msg;
  9616. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  9617. Error(msg.AddressOf(), ctx->exprNode);
  9618. }
  9619. int argSize = descr->GetSpaceNeededForArguments();
  9620. if( descr->objectType && descr->returnType.IsReference() &&
  9621. !ctx->type.isVariable && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  9622. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  9623. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  9624. {
  9625. // The class method we're calling is returning a reference, which may be to a member of the object.
  9626. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  9627. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  9628. int tempRef = AllocateVariable(ctx->type.dataType, true);
  9629. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  9630. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9631. // Add the release of this reference, as a deferred expression
  9632. asSDeferredParam deferred;
  9633. deferred.origExpr = 0;
  9634. deferred.argInOutFlags = asTM_INREF;
  9635. deferred.argNode = 0;
  9636. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  9637. ctx->deferredParams.PushLast(deferred);
  9638. // Forget the current type
  9639. ctx->type.SetDummy();
  9640. }
  9641. if( isConstructor )
  9642. {
  9643. // Sometimes the value types are allocated on the heap,
  9644. // which is when this way of constructing them is used.
  9645. asASSERT(useVariable == false);
  9646. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  9647. // The instruction has already moved the returned object to the variable
  9648. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  9649. ctx->type.isLValue = false;
  9650. // Clean up arguments
  9651. if( args )
  9652. AfterFunctionCall(funcId, *args, ctx, false);
  9653. ProcessDeferredParams(ctx);
  9654. return;
  9655. }
  9656. else
  9657. {
  9658. if( descr->objectType )
  9659. argSize += AS_PTR_SIZE;
  9660. // If the function returns an object by value the address of the location
  9661. // where the value should be stored is passed as an argument too
  9662. if( descr->DoesReturnOnStack() )
  9663. {
  9664. argSize += AS_PTR_SIZE;
  9665. }
  9666. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  9667. // should be made with asBC_CALL as it is faster. Examples where this
  9668. // is known is for example finalled methods where the class doesn't derive
  9669. // from any other, or even non-finalled methods but where it is known
  9670. // at compile time the true type of the object. The first should be
  9671. // quite easy to determine, but the latter will be quite complex and possibly
  9672. // not worth it.
  9673. if( descr->funcType == asFUNC_IMPORTED )
  9674. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  9675. // TODO: Maybe we need two different byte codes
  9676. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  9677. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  9678. else if( descr->funcType == asFUNC_SCRIPT )
  9679. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  9680. else if( descr->funcType == asFUNC_SYSTEM )
  9681. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  9682. else if( descr->funcType == asFUNC_FUNCDEF )
  9683. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  9684. }
  9685. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  9686. {
  9687. int returnOffset = 0;
  9688. if( descr->DoesReturnOnStack() )
  9689. {
  9690. asASSERT( useVariable );
  9691. // The variable was allocated before the function was called
  9692. returnOffset = varOffset;
  9693. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9694. // The variable was initialized by the function, so we need to mark it as initialized here
  9695. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  9696. }
  9697. else
  9698. {
  9699. if( useVariable )
  9700. {
  9701. // Use the given variable
  9702. returnOffset = varOffset;
  9703. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  9704. }
  9705. else
  9706. {
  9707. // Allocate a temporary variable for the returned object
  9708. // The returned object will actually be allocated on the heap, so
  9709. // we must force the allocation of the variable to do the same
  9710. returnOffset = AllocateVariable(descr->returnType, true, true);
  9711. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9712. }
  9713. // Move the pointer from the object register to the temporary variable
  9714. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9715. }
  9716. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  9717. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  9718. // Clean up arguments
  9719. if( args )
  9720. AfterFunctionCall(funcId, *args, ctx, false);
  9721. ProcessDeferredParams(ctx);
  9722. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9723. }
  9724. else if( descr->returnType.IsReference() )
  9725. {
  9726. asASSERT(useVariable == false);
  9727. // We cannot clean up the arguments yet, because the
  9728. // reference might be pointing to one of them.
  9729. if( args )
  9730. AfterFunctionCall(funcId, *args, ctx, true);
  9731. // Do not process the output parameters yet, because it
  9732. // might invalidate the returned reference
  9733. // If the context holds a variable that needs cleanup
  9734. // store it as a deferred parameter so it will be cleaned up
  9735. // afterwards.
  9736. if( ctx->type.isTemporary )
  9737. {
  9738. asSDeferredParam defer;
  9739. defer.argNode = 0;
  9740. defer.argType = ctx->type;
  9741. defer.argInOutFlags = asTM_INOUTREF;
  9742. defer.origExpr = 0;
  9743. ctx->deferredParams.PushLast(defer);
  9744. }
  9745. ctx->type.Set(descr->returnType);
  9746. if( !descr->returnType.IsPrimitive() )
  9747. {
  9748. ctx->bc.Instr(asBC_PshRPtr);
  9749. if( descr->returnType.IsObject() &&
  9750. !descr->returnType.IsObjectHandle() )
  9751. {
  9752. // We are getting the pointer to the object
  9753. // not a pointer to a object variable
  9754. ctx->type.dataType.MakeReference(false);
  9755. }
  9756. }
  9757. // A returned reference can be used as lvalue
  9758. ctx->type.isLValue = true;
  9759. }
  9760. else
  9761. {
  9762. asASSERT(useVariable == false);
  9763. if( descr->returnType.GetSizeInMemoryBytes() )
  9764. {
  9765. // Allocate a temporary variable to hold the value, but make sure
  9766. // the temporary variable isn't used in any of the deferred arguments
  9767. int l = int(reservedVariables.GetLength());
  9768. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  9769. {
  9770. asSExprContext *expr = (*args)[n]->origExpr;
  9771. if( expr )
  9772. expr->bc.GetVarsUsed(reservedVariables);
  9773. }
  9774. int offset = AllocateVariable(descr->returnType, true);
  9775. reservedVariables.SetLength(l);
  9776. ctx->type.SetVariable(descr->returnType, offset, true);
  9777. // Move the value from the return register to the variable
  9778. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  9779. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  9780. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  9781. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  9782. }
  9783. else
  9784. ctx->type.Set(descr->returnType);
  9785. ctx->type.isLValue = false;
  9786. // Clean up arguments
  9787. if( args )
  9788. AfterFunctionCall(funcId, *args, ctx, false);
  9789. ProcessDeferredParams(ctx);
  9790. }
  9791. }
  9792. // This only merges the bytecode, but doesn't modify the type of the final context
  9793. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  9794. {
  9795. before->bc.AddCode(&after->bc);
  9796. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  9797. {
  9798. before->deferredParams.PushLast(after->deferredParams[n]);
  9799. after->deferredParams[n].origExpr = 0;
  9800. }
  9801. after->deferredParams.SetLength(0);
  9802. }
  9803. // This merges both bytecode and the type of the final context
  9804. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  9805. {
  9806. MergeExprBytecode(before, after);
  9807. before->type = after->type;
  9808. before->property_get = after->property_get;
  9809. before->property_set = after->property_set;
  9810. before->property_const = after->property_const;
  9811. before->property_handle = after->property_handle;
  9812. before->property_ref = after->property_ref;
  9813. before->property_arg = after->property_arg;
  9814. before->exprNode = after->exprNode;
  9815. after->property_arg = 0;
  9816. // Do not copy the origExpr member
  9817. }
  9818. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  9819. {
  9820. if( funcs.GetLength() == 0 ) return;
  9821. // This is only done for object methods
  9822. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  9823. if( desc->objectType == 0 ) return;
  9824. // Check if there are any non-const matches
  9825. asUINT n;
  9826. bool foundNonConst = false;
  9827. for( n = 0; n < funcs.GetLength(); n++ )
  9828. {
  9829. desc = builder->GetFunctionDescription(funcs[n]);
  9830. if( desc->isReadOnly != removeConst )
  9831. {
  9832. foundNonConst = true;
  9833. break;
  9834. }
  9835. }
  9836. if( foundNonConst )
  9837. {
  9838. // Remove all const methods
  9839. for( n = 0; n < funcs.GetLength(); n++ )
  9840. {
  9841. desc = builder->GetFunctionDescription(funcs[n]);
  9842. if( desc->isReadOnly == removeConst )
  9843. {
  9844. if( n == funcs.GetLength() - 1 )
  9845. funcs.PopLast();
  9846. else
  9847. funcs[n] = funcs.PopLast();
  9848. n--;
  9849. }
  9850. }
  9851. }
  9852. }
  9853. END_AS_NAMESPACE
  9854. #endif // AS_NO_COMPILER