as_compiler.cpp 323 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2011 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. #include "as_compiler.h"
  32. #include "as_tokendef.h"
  33. #include "as_tokenizer.h"
  34. #include "as_string_util.h"
  35. #include "as_texts.h"
  36. #include "as_parser.h"
  37. BEGIN_AS_NAMESPACE
  38. // TODO: I must correct the interpretation of a references to objects in the compiler.
  39. // A reference should mean that a pointer to the object is on the stack.
  40. // No expression should end up as non-references to objects, as the actual object is
  41. // never put on the stack.
  42. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  43. // Function parameters of called functions can also be non-references, but in that case it means the
  44. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  45. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  46. {
  47. builder = 0;
  48. script = 0;
  49. variables = 0;
  50. isProcessingDeferredParams = false;
  51. noCodeOutput = 0;
  52. }
  53. asCCompiler::~asCCompiler()
  54. {
  55. while( variables )
  56. {
  57. asCVariableScope *var = variables;
  58. variables = variables->parent;
  59. asDELETE(var,asCVariableScope);
  60. }
  61. }
  62. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  63. {
  64. this->builder = builder;
  65. this->engine = builder->engine;
  66. this->script = script;
  67. this->outFunc = outFunc;
  68. hasCompileErrors = false;
  69. m_isConstructor = false;
  70. m_isConstructorCalled = false;
  71. nextLabel = 0;
  72. breakLabels.SetLength(0);
  73. continueLabels.SetLength(0);
  74. byteCode.ClearAll();
  75. globalExpression = false;
  76. }
  77. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  78. {
  79. Reset(builder, script, outFunc);
  80. // If the class is derived from another, then the base class' default constructor must be called
  81. if( outFunc->objectType->derivedFrom )
  82. {
  83. // Call the base class' default constructor
  84. byteCode.InstrSHORT(asBC_PSF, 0);
  85. byteCode.Instr(asBC_RDSPTR);
  86. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  87. }
  88. // Pop the object pointer from the stack
  89. byteCode.Ret(AS_PTR_SIZE);
  90. FinalizeFunction();
  91. #ifdef AS_DEBUG
  92. // DEBUG: output byte code
  93. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__dc.txt").AddressOf(), engine, outFunc);
  94. #endif
  95. return 0;
  96. }
  97. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  98. {
  99. Reset(builder, script, outFunc);
  100. unsigned int n;
  101. // Find the corresponding constructor
  102. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  103. int constructor = 0;
  104. for( n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  105. {
  106. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  107. {
  108. constructor = dt.GetBehaviour()->constructors[n];
  109. break;
  110. }
  111. }
  112. // Allocate the class and instanciate it with the constructor
  113. int varOffset = AllocateVariable(dt, true);
  114. byteCode.Push(AS_PTR_SIZE);
  115. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  116. // Copy all arguments to the top of the stack
  117. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  118. for( int a = argDwords-1; a >= 0; a-- )
  119. byteCode.InstrSHORT(asBC_PshV4, short(-a));
  120. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  121. // Return a handle to the newly created object
  122. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  123. byteCode.Ret(argDwords);
  124. FinalizeFunction();
  125. // Tell the virtual machine not to clean up parameters on exception
  126. outFunc->dontCleanUpOnException = true;
  127. /*
  128. #ifdef AS_DEBUG
  129. // DEBUG: output byte code
  130. asCString args;
  131. args.Format("%d", outFunc->parameterTypes.GetLength());
  132. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  133. #endif
  134. */
  135. return 0;
  136. }
  137. // Entry
  138. int asCCompiler::CompileTemplateFactoryStub(asCBuilder *builder, int trueFactoryId, asCObjectType *objType, asCScriptFunction *outFunc)
  139. {
  140. Reset(builder, 0, outFunc);
  141. asCScriptFunction *descr = builder->GetFunctionDescription(trueFactoryId);
  142. byteCode.InstrPTR(asBC_OBJTYPE, objType);
  143. byteCode.Call(asBC_CALLSYS, trueFactoryId, descr->GetSpaceNeededForArguments());
  144. byteCode.Ret(outFunc->GetSpaceNeededForArguments());
  145. FinalizeFunction();
  146. // Tell the virtual machine not to clean up the object on exception
  147. outFunc->dontCleanUpOnException = true;
  148. return 0;
  149. }
  150. // Entry
  151. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCScriptNode *func, asCScriptFunction *outFunc)
  152. {
  153. Reset(builder, script, outFunc);
  154. int buildErrors = builder->numErrors;
  155. int stackPos = 0;
  156. if( outFunc->objectType )
  157. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  158. // Reserve a label for the cleanup code
  159. nextLabel++;
  160. // Add the first variable scope, which the parameters and
  161. // variables declared in the outermost statement block is
  162. // part of.
  163. AddVariableScope();
  164. //----------------------------------------------
  165. // Examine return type
  166. bool isDestructor = false;
  167. asCDataType returnType;
  168. if( func->firstChild->nodeType == snDataType )
  169. {
  170. returnType = builder->CreateDataTypeFromNode(func->firstChild, script);
  171. returnType = builder->ModifyDataTypeFromNode(returnType, func->firstChild->next, script, 0, 0);
  172. // Make sure the return type is instanciable or is void
  173. if( !returnType.CanBeInstanciated() &&
  174. returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  175. {
  176. asCString str;
  177. str.Format(TXT_DATA_TYPE_CANT_BE_s, returnType.Format().AddressOf());
  178. Error(str.AddressOf(), func->firstChild);
  179. }
  180. }
  181. else
  182. {
  183. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  184. if( func->firstChild->tokenType == ttBitNot )
  185. isDestructor = true;
  186. else
  187. m_isConstructor = true;
  188. }
  189. //----------------------------------------------
  190. // Declare parameters
  191. // Find first parameter
  192. asCScriptNode *node = func->firstChild;
  193. while( node && node->nodeType != snParameterList )
  194. node = node->next;
  195. // Register parameters from last to first, otherwise they will be destroyed in the wrong order
  196. asCVariableScope vs(0);
  197. if( node ) node = node->firstChild;
  198. while( node )
  199. {
  200. // Get the parameter type
  201. asCDataType type = builder->CreateDataTypeFromNode(node, script);
  202. asETypeModifiers inoutFlag = asTM_NONE;
  203. type = builder->ModifyDataTypeFromNode(type, node->next, script, &inoutFlag, 0);
  204. // Is the data type allowed?
  205. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  206. (!type.IsReference() && !type.CanBeInstanciated()) )
  207. {
  208. asCString str;
  209. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  210. Error(str.AddressOf(), node);
  211. }
  212. // If the parameter has a name then declare it as variable
  213. node = node->next->next;
  214. if( node && node->nodeType == snIdentifier )
  215. {
  216. asCString name(&script->code[node->tokenPos], node->tokenLength);
  217. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  218. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  219. outFunc->AddVariable(name, type, stackPos);
  220. node = node->next;
  221. }
  222. else
  223. vs.DeclareVariable("", type, stackPos, true);
  224. // Move to next parameter
  225. stackPos -= type.GetSizeOnStackDWords();
  226. }
  227. int n;
  228. for( n = (int)vs.variables.GetLength() - 1; n >= 0; n-- )
  229. {
  230. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  231. }
  232. // Is the return type allowed?
  233. if( (returnType.GetSizeOnStackDWords() == 0 && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  234. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  235. {
  236. asCString str;
  237. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  238. Error(str.AddressOf(), node);
  239. }
  240. variables->DeclareVariable("return", returnType, stackPos, true);
  241. //--------------------------------------------
  242. // Compile the statement block
  243. // We need to parse the statement block now
  244. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  245. asCParser parser(builder);
  246. int r = parser.ParseStatementBlock(script, func->lastChild);
  247. if( r < 0 ) return -1;
  248. asCScriptNode *block = parser.GetScriptNode();
  249. bool hasReturn;
  250. asCByteCode bc(engine);
  251. LineInstr(&bc, func->lastChild->tokenPos);
  252. CompileStatementBlock(block, false, &hasReturn, &bc);
  253. LineInstr(&bc, func->lastChild->tokenPos + func->lastChild->tokenLength);
  254. // Make sure there is a return in all paths (if not return type is void)
  255. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  256. {
  257. if( hasReturn == false )
  258. Error(TXT_NOT_ALL_PATHS_RETURN, func->lastChild);
  259. }
  260. //------------------------------------------------
  261. // Concatenate the bytecode
  262. // Insert a JitEntry at the start of the function for JIT compilers
  263. byteCode.InstrWORD(asBC_JitEntry, 0);
  264. // Count total variable size
  265. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  266. byteCode.Push(varSize);
  267. if( outFunc->objectType )
  268. {
  269. // Call the base class' default constructor unless called manually in the code
  270. if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
  271. {
  272. byteCode.InstrSHORT(asBC_PSF, 0);
  273. byteCode.Instr(asBC_RDSPTR);
  274. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  275. }
  276. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  277. // TODO: optimize: This is probably not necessary for constructors as no outside reference to the object is created yet
  278. byteCode.InstrSHORT(asBC_PSF, 0);
  279. byteCode.Instr(asBC_RDSPTR);
  280. byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  281. }
  282. // Add the code for the statement block
  283. byteCode.AddCode(&bc);
  284. // Deallocate all local variables
  285. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  286. {
  287. sVariable *v = variables->variables[n];
  288. if( v->stackOffset > 0 )
  289. {
  290. // Call variables destructors
  291. if( v->name != "return" && v->name != "return address" )
  292. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  293. DeallocateVariable(v->stackOffset);
  294. }
  295. }
  296. // This is the label that return statements jump to
  297. // in order to exit the function
  298. byteCode.Label(0);
  299. // Call destructors for function parameters
  300. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  301. {
  302. sVariable *v = variables->variables[n];
  303. if( v->stackOffset <= 0 )
  304. {
  305. // Call variable destructors here, for variables not yet destroyed
  306. if( v->name != "return" && v->name != "return address" )
  307. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  308. }
  309. // Do not deallocate parameters
  310. }
  311. // Release the object pointer again
  312. if( outFunc->objectType )
  313. {
  314. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  315. }
  316. // If there are compile errors, there is no reason to build the final code
  317. if( hasCompileErrors || builder->numErrors != buildErrors )
  318. return -1;
  319. // At this point there should be no variables allocated
  320. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  321. // Remove the variable scope
  322. RemoveVariableScope();
  323. // This POP is not necessary as the return will clean up the stack frame anyway.
  324. // The bytecode optimizer would remove this POP, however by not including it here
  325. // it is guaranteed it doesn't have to be adjusted by the asCRestore class when
  326. // a types are of a different size than originally compiled for.
  327. // byteCode.Pop(varSize);
  328. byteCode.Ret(-stackPos);
  329. FinalizeFunction();
  330. #ifdef AS_DEBUG
  331. // DEBUG: output byte code
  332. if( outFunc->objectType )
  333. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  334. else
  335. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  336. #endif
  337. return 0;
  338. }
  339. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar)
  340. {
  341. if( !type.IsObject() )
  342. return 0;
  343. // CallCopyConstructor should not be called for object handles.
  344. asASSERT(!type.IsObjectHandle());
  345. asCArray<asSExprContext*> args;
  346. args.PushLast(arg);
  347. // The reference parameter must be pushed on the stack
  348. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  349. // Since we're calling the copy constructor, we have to trust the function to not do
  350. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  351. // copies of the argument in order to guarantee safety.
  352. if( type.GetObjectType()->flags & asOBJ_REF )
  353. {
  354. asSExprContext ctx(engine);
  355. int func = 0;
  356. asSTypeBehaviour *beh = type.GetBehaviour();
  357. if( beh ) func = beh->copyfactory;
  358. if( func > 0 )
  359. {
  360. if( !isGlobalVar )
  361. {
  362. // Call factory and store the handle in the given variable
  363. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  364. // Pop the reference left by the function call
  365. ctx.bc.Pop(AS_PTR_SIZE);
  366. }
  367. else
  368. {
  369. // Call factory
  370. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  371. // Store the returned handle in the global variable
  372. ctx.bc.Instr(asBC_RDSPTR);
  373. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  374. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  375. ctx.bc.Pop(AS_PTR_SIZE);
  376. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  377. }
  378. bc->AddCode(&ctx.bc);
  379. return 0;
  380. }
  381. }
  382. else
  383. {
  384. asSTypeBehaviour *beh = type.GetBehaviour();
  385. int func = beh ? beh->copyconstruct : 0;
  386. if( func > 0 )
  387. {
  388. // Push the address where the object will be stored on the stack, before the argument
  389. // TODO: When the context is serializable this probably has to be changed, since this
  390. // pointer can remain on the stack while the context is suspended. There is no
  391. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  392. asCByteCode tmp(engine);
  393. if( isGlobalVar )
  394. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  395. else if( isObjectOnHeap )
  396. tmp.InstrSHORT(asBC_PSF, (short)offset);
  397. tmp.AddCode(bc);
  398. bc->AddCode(&tmp);
  399. // When the object is allocated on the stack the object pointer
  400. // must be pushed on the stack after the arguments
  401. if( !isObjectOnHeap )
  402. {
  403. asASSERT( !isGlobalVar );
  404. bc->InstrSHORT(asBC_PSF, (short)offset);
  405. }
  406. asSExprContext ctx(engine);
  407. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  408. bc->AddCode(&ctx.bc);
  409. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  410. // Mark the object as initialized
  411. if( !isObjectOnHeap )
  412. bc->ObjInfo(offset, asOBJ_INIT);
  413. return 0;
  414. }
  415. }
  416. // Class has no copy constructor/factory.
  417. asCString str;
  418. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  419. Error(str.AddressOf(), node);
  420. return -1;
  421. }
  422. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, bool isGlobalVar)
  423. {
  424. if( !type.IsObject() || type.IsObjectHandle() )
  425. return 0;
  426. if( type.GetObjectType()->flags & asOBJ_REF )
  427. {
  428. asSExprContext ctx(engine);
  429. int func = 0;
  430. asSTypeBehaviour *beh = type.GetBehaviour();
  431. if( beh ) func = beh->factory;
  432. if( func > 0 )
  433. {
  434. if( !isGlobalVar )
  435. {
  436. // Call factory and store the handle in the given variable
  437. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  438. // Pop the reference left by the function call
  439. ctx.bc.Pop(AS_PTR_SIZE);
  440. }
  441. else
  442. {
  443. // Call factory
  444. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  445. // Store the returned handle in the global variable
  446. ctx.bc.Instr(asBC_RDSPTR);
  447. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  448. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  449. ctx.bc.Pop(AS_PTR_SIZE);
  450. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  451. }
  452. bc->AddCode(&ctx.bc);
  453. return 0;
  454. }
  455. }
  456. else
  457. {
  458. asSTypeBehaviour *beh = type.GetBehaviour();
  459. int func = 0;
  460. if( beh ) func = beh->construct;
  461. // Allocate and initialize with the default constructor
  462. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  463. {
  464. if( !isObjectOnHeap )
  465. {
  466. asASSERT( !isGlobalVar );
  467. // There is nothing to do if there is no function,
  468. // as the memory is already allocated on the stack
  469. if( func )
  470. {
  471. // Call the constructor as a normal function
  472. bc->InstrSHORT(asBC_PSF, (short)offset);
  473. asSExprContext ctx(engine);
  474. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  475. bc->AddCode(&ctx.bc);
  476. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  477. // Mark the object as initialized
  478. bc->ObjInfo(offset, asOBJ_INIT);
  479. }
  480. }
  481. else
  482. {
  483. if( isGlobalVar )
  484. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  485. else
  486. bc->InstrSHORT(asBC_PSF, (short)offset);
  487. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  488. }
  489. return 0;
  490. }
  491. }
  492. // Class has no default factory/constructor.
  493. asCString str;
  494. // TODO: funcdef: asCDataType should have a GetTypeName()
  495. if( type.GetFuncDef() )
  496. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  497. else
  498. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  499. Error(str.AddressOf(), node);
  500. return -1;
  501. }
  502. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  503. {
  504. if( !type.IsReference() )
  505. {
  506. // Call destructor for the data type
  507. if( type.IsObject() )
  508. {
  509. if( isObjectOnHeap || type.IsObjectHandle() )
  510. {
  511. // Free the memory
  512. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  513. }
  514. else
  515. {
  516. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  517. if( type.GetBehaviour()->destruct )
  518. {
  519. // Call the destructor as a regular function
  520. bc->InstrSHORT(asBC_PSF, offset);
  521. asSExprContext ctx(engine);
  522. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  523. bc->AddCode(&ctx.bc);
  524. }
  525. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  526. // Mark the object as destroyed
  527. bc->ObjInfo(offset, asOBJ_UNINIT);
  528. }
  529. }
  530. }
  531. }
  532. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  533. {
  534. int r, c;
  535. script->ConvertPosToRowCol(pos, &r, &c);
  536. bc->Line(r, c);
  537. }
  538. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  539. {
  540. *hasReturn = false;
  541. bool isFinished = false;
  542. bool hasWarned = false;
  543. if( ownVariableScope )
  544. {
  545. bc->Block(true);
  546. AddVariableScope();
  547. }
  548. asCScriptNode *node = block->firstChild;
  549. while( node )
  550. {
  551. if( !hasWarned && (*hasReturn || isFinished) )
  552. {
  553. hasWarned = true;
  554. Warning(TXT_UNREACHABLE_CODE, node);
  555. }
  556. if( node->nodeType == snBreak || node->nodeType == snContinue )
  557. isFinished = true;
  558. asCByteCode statement(engine);
  559. if( node->nodeType == snDeclaration )
  560. CompileDeclaration(node, &statement);
  561. else
  562. CompileStatement(node, hasReturn, &statement);
  563. LineInstr(bc, node->tokenPos);
  564. bc->AddCode(&statement);
  565. if( !hasCompileErrors )
  566. asASSERT( tempVariables.GetLength() == 0 );
  567. node = node->next;
  568. }
  569. if( ownVariableScope )
  570. {
  571. // Deallocate variables in this block, in reverse order
  572. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  573. {
  574. sVariable *v = variables->variables[n];
  575. // Call variable destructors here, for variables not yet destroyed
  576. // If the block is terminated with a break, continue, or
  577. // return the variables are already destroyed
  578. if( !isFinished && !*hasReturn )
  579. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  580. // Don't deallocate function parameters
  581. if( v->stackOffset > 0 )
  582. DeallocateVariable(v->stackOffset);
  583. }
  584. RemoveVariableScope();
  585. bc->Block(false);
  586. }
  587. }
  588. // Entry
  589. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  590. {
  591. Reset(builder, script, outFunc);
  592. globalExpression = true;
  593. // Add a variable scope (even though variables can't be declared)
  594. AddVariableScope();
  595. asSExprContext ctx(engine);
  596. gvar->isPureConstant = false;
  597. // Parse the initialization nodes
  598. asCParser parser(builder);
  599. if( node )
  600. {
  601. int r = parser.ParseGlobalVarInit(script, node);
  602. if( r < 0 )
  603. return r;
  604. node = parser.GetScriptNode();
  605. }
  606. // Compile the expression
  607. if( node && node->nodeType == snArgList )
  608. {
  609. // Make sure that it is a registered type, and that it isn't a pointer
  610. if( gvar->datatype.GetObjectType() == 0 || gvar->datatype.IsObjectHandle() )
  611. {
  612. Error(TXT_MUST_BE_OBJECT, node);
  613. }
  614. else
  615. {
  616. // Compile the arguments
  617. asCArray<asSExprContext *> args;
  618. if( CompileArgumentList(node, args) >= 0 )
  619. {
  620. // Find all constructors
  621. asCArray<int> funcs;
  622. asSTypeBehaviour *beh = gvar->datatype.GetBehaviour();
  623. if( beh )
  624. {
  625. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  626. funcs = beh->factories;
  627. else
  628. funcs = beh->constructors;
  629. }
  630. asCString str = gvar->datatype.Format();
  631. MatchFunctions(funcs, args, node, str.AddressOf());
  632. if( funcs.GetLength() == 1 )
  633. {
  634. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  635. {
  636. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  637. // Store the returned handle in the global variable
  638. ctx.bc.Instr(asBC_RDSPTR);
  639. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  640. ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
  641. ctx.bc.Pop(AS_PTR_SIZE);
  642. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  643. }
  644. else
  645. {
  646. // Push the address of the location where the variable will be stored on the stack.
  647. // This reference is safe, because the addresses of the global variables cannot change.
  648. // TODO: When serialization of the context is implemented this will probably have to change,
  649. // because this pointer may be on the stack while the context is suspended, and may
  650. // be difficult to serialize as the context doesn't know that the value represents a
  651. // pointer.
  652. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  653. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  654. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  655. PerformFunctionCall(funcs[0], &ctx, true, &args, gvar->datatype.GetObjectType());
  656. }
  657. }
  658. }
  659. // Cleanup
  660. for( asUINT n = 0; n < args.GetLength(); n++ )
  661. if( args[n] )
  662. {
  663. asDELETE(args[n],asSExprContext);
  664. }
  665. }
  666. }
  667. else if( node && node->nodeType == snInitList )
  668. {
  669. asCTypeInfo ti;
  670. ti.Set(gvar->datatype);
  671. ti.isVariable = false;
  672. ti.isTemporary = false;
  673. ti.stackOffset = (short)gvar->index;
  674. CompileInitList(&ti, node, &ctx.bc);
  675. node = node->next;
  676. }
  677. else if( node )
  678. {
  679. // Compile the right hand expression
  680. asSExprContext expr(engine);
  681. int r = CompileAssignment(node, &expr); if( r < 0 ) return r;
  682. // Assign the value to the variable
  683. if( gvar->datatype.IsPrimitive() )
  684. {
  685. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  686. {
  687. ImplicitConversion(&expr, gvar->datatype, node, asIC_IMPLICIT_CONV);
  688. gvar->isPureConstant = true;
  689. gvar->constantValue = expr.type.qwordValue;
  690. }
  691. asSExprContext lctx(engine);
  692. lctx.type.Set(gvar->datatype);
  693. lctx.type.dataType.MakeReference(true);
  694. lctx.type.dataType.MakeReadOnly(false);
  695. // If it is an enum value that is being compiled, then
  696. // we skip this, as the bytecode won't be used anyway
  697. if( !gvar->isEnumValue )
  698. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[gvar->index]->GetAddressOfValue());
  699. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  700. }
  701. else
  702. {
  703. // TODO: copy: Here we should look for the best matching constructor, instead of
  704. // just the copy constructor. Only if no appropriate constructor is
  705. // available should the assignment operator be used.
  706. if( !gvar->datatype.IsObjectHandle() )
  707. {
  708. // Call the default constructor to have a valid object for the assignment
  709. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  710. }
  711. asSExprContext lexpr(engine);
  712. lexpr.type.Set(gvar->datatype);
  713. lexpr.type.dataType.MakeReference(true);
  714. lexpr.type.dataType.MakeReadOnly(false);
  715. lexpr.type.stackOffset = -1;
  716. if( gvar->datatype.IsObjectHandle() )
  717. lexpr.type.isExplicitHandle = true;
  718. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  719. // If left expression resolves into a registered type
  720. // check if the assignment operator is overloaded, and check
  721. // the type of the right hand expression. If none is found
  722. // the default action is a direct copy if it is the same type
  723. // and a simple assignment.
  724. bool assigned = false;
  725. if( lexpr.type.dataType.IsObject() && !lexpr.type.isExplicitHandle )
  726. {
  727. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  728. if( assigned )
  729. {
  730. // Pop the resulting value
  731. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  732. // Release the argument
  733. ProcessDeferredParams(&ctx);
  734. }
  735. }
  736. if( !assigned )
  737. {
  738. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  739. // If the expression is constant and the variable also is constant
  740. // then mark the variable as pure constant. This will allow the compiler
  741. // to optimize expressions with this variable.
  742. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  743. {
  744. gvar->isPureConstant = true;
  745. gvar->constantValue = expr.type.qwordValue;
  746. }
  747. // Add expression code to bytecode
  748. MergeExprBytecode(&ctx, &expr);
  749. // Add byte code for storing value of expression in variable
  750. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  751. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node);
  752. // Release temporary variables used by expression
  753. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  754. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  755. }
  756. }
  757. }
  758. else if( gvar->datatype.IsObject() && !gvar->datatype.IsObjectHandle() )
  759. {
  760. // Call the default constructor in case no explicit initialization is given
  761. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  762. }
  763. // Concatenate the bytecode
  764. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  765. // Add information on the line number for the global variable
  766. size_t pos = 0;
  767. if( gvar->idNode )
  768. pos = gvar->idNode->tokenPos;
  769. else if( gvar->nextNode )
  770. pos = gvar->nextNode->tokenPos;
  771. LineInstr(&byteCode, pos);
  772. // We need to push zeroes on the stack to guarantee
  773. // that temporary object handles are clear
  774. int n;
  775. for( n = 0; n < varSize; n++ )
  776. byteCode.InstrINT(asBC_PshC4, 0);
  777. byteCode.AddCode(&ctx.bc);
  778. // Deallocate variables in this block, in reverse order
  779. for( n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  780. {
  781. sVariable *v = variables->variables[n];
  782. // Call variable destructors here, for variables not yet destroyed
  783. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  784. DeallocateVariable(v->stackOffset);
  785. }
  786. if( hasCompileErrors ) return -1;
  787. // At this point there should be no variables allocated
  788. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  789. // Remove the variable scope again
  790. RemoveVariableScope();
  791. byteCode.Ret(0);
  792. FinalizeFunction();
  793. #ifdef AS_DEBUG
  794. // DEBUG: output byte code
  795. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  796. #endif
  797. return 0;
  798. }
  799. void asCCompiler::FinalizeFunction()
  800. {
  801. asUINT n;
  802. // Tell the bytecode which variables are temporary
  803. for( n = 0; n < variableIsTemporary.GetLength(); n++ )
  804. {
  805. if( variableIsTemporary[n] )
  806. byteCode.DefineTemporaryVariable(GetVariableOffset(n));
  807. }
  808. // Finalize the bytecode
  809. byteCode.Finalize();
  810. byteCode.ExtractObjectVariableInfo(outFunc);
  811. // Compile the list of object variables for the exception handler
  812. for( n = 0; n < variableAllocations.GetLength(); n++ )
  813. {
  814. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  815. {
  816. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  817. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  818. outFunc->objVariableIsOnHeap.PushLast(variableIsOnHeap[n]);
  819. }
  820. }
  821. // Copy byte code to the function
  822. outFunc->byteCode.SetLength(byteCode.GetSize());
  823. byteCode.Output(outFunc->byteCode.AddressOf());
  824. outFunc->AddReferences();
  825. outFunc->stackNeeded = byteCode.largestStackUsed;
  826. outFunc->lineNumbers = byteCode.lineNumbers;
  827. }
  828. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, asCArray<int> *reservedVars, bool forceOnHeap)
  829. {
  830. asCDataType param = *paramType;
  831. if( paramType->GetTokenType() == ttQuestion )
  832. {
  833. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  834. param = ctx->type.dataType;
  835. param.MakeHandle(ctx->type.isExplicitHandle);
  836. param.MakeReference(paramType->IsReference());
  837. param.MakeReadOnly(paramType->IsReadOnly());
  838. }
  839. else
  840. param = *paramType;
  841. asCDataType dt = param;
  842. // Need to protect arguments by reference
  843. if( isFunction && dt.IsReference() )
  844. {
  845. if( paramType->GetTokenType() == ttQuestion )
  846. {
  847. asCByteCode tmpBC(engine);
  848. // Place the type id on the stack as a hidden parameter
  849. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  850. // Insert the code before the expression code
  851. tmpBC.AddCode(&ctx->bc);
  852. ctx->bc.AddCode(&tmpBC);
  853. }
  854. // Allocate a temporary variable of the same type as the argument
  855. dt.MakeReference(false);
  856. dt.MakeReadOnly(false);
  857. int offset;
  858. if( refType == 1 ) // &in
  859. {
  860. ProcessPropertyGetAccessor(ctx, node);
  861. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  862. // Even if the same variable is passed in another argument as non-const then there is no problem
  863. if( dt.IsPrimitive() || dt.IsNullHandle() )
  864. {
  865. IsVariableInitialized(&ctx->type, node);
  866. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  867. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  868. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  869. ConvertToTempVariable(ctx);
  870. PushVariableOnStack(ctx, true);
  871. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  872. }
  873. else
  874. {
  875. IsVariableInitialized(&ctx->type, node);
  876. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, reservedVars);
  877. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  878. {
  879. asCString str;
  880. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  881. Error(str.AddressOf(), node);
  882. ctx->type.Set(param);
  883. }
  884. // If the argument already is a temporary
  885. // variable we don't need to allocate another
  886. // If the parameter is read-only and the object already is a local
  887. // variable then it is not necessary to make a copy either
  888. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  889. {
  890. // Make sure the variable is not used in the expression
  891. asCArray<int> vars;
  892. ctx->bc.GetVarsUsed(vars);
  893. if( reservedVars ) vars.Concatenate(*reservedVars);
  894. offset = AllocateVariableNotIn(dt, true, &vars);
  895. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  896. // Allocate and construct the temporary object
  897. asCByteCode tmpBC(engine);
  898. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  899. // Insert the code before the expression code
  900. tmpBC.AddCode(&ctx->bc);
  901. ctx->bc.AddCode(&tmpBC);
  902. // Assign the evaluated expression to the temporary variable
  903. PrepareForAssignment(&dt, ctx, node);
  904. dt.MakeReference(IsVariableOnHeap(offset));
  905. asCTypeInfo type;
  906. type.Set(dt);
  907. type.isTemporary = true;
  908. type.stackOffset = (short)offset;
  909. if( dt.IsObjectHandle() )
  910. type.isExplicitHandle = true;
  911. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  912. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  913. ctx->bc.Pop(ctx->type.dataType.GetSizeOnStackDWords());
  914. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  915. ctx->type = type;
  916. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  917. if( dt.IsObject() && !dt.IsObjectHandle() )
  918. ctx->bc.Instr(asBC_RDSPTR);
  919. if( paramType->IsReadOnly() )
  920. ctx->type.dataType.MakeReadOnly(true);
  921. }
  922. }
  923. }
  924. else if( refType == 2 ) // &out
  925. {
  926. // Make sure the variable is not used in the expression
  927. asCArray<int> vars;
  928. ctx->bc.GetVarsUsed(vars);
  929. if( reservedVars ) vars.Concatenate(*reservedVars);
  930. offset = AllocateVariableNotIn(dt, true, &vars);
  931. if( dt.IsPrimitive() )
  932. {
  933. ctx->type.SetVariable(dt, offset, true);
  934. PushVariableOnStack(ctx, true);
  935. }
  936. else
  937. {
  938. // Allocate and construct the temporary object
  939. asCByteCode tmpBC(engine);
  940. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  941. // Insert the code before the expression code
  942. tmpBC.AddCode(&ctx->bc);
  943. ctx->bc.AddCode(&tmpBC);
  944. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  945. asCTypeInfo type;
  946. type.Set(dt);
  947. type.isTemporary = true;
  948. type.stackOffset = (short)offset;
  949. ctx->type = type;
  950. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  951. if( dt.IsObject() && !dt.IsObjectHandle() )
  952. ctx->bc.Instr(asBC_RDSPTR);
  953. }
  954. // After the function returns the temporary variable will
  955. // be assigned to the expression, if it is a valid lvalue
  956. }
  957. else if( refType == asTM_INOUTREF )
  958. {
  959. // Literal constants cannot be passed to inout ref arguments
  960. if( !ctx->type.isVariable && ctx->type.isConstant )
  961. {
  962. Error(TXT_NOT_VALID_REFERENCE, node);
  963. }
  964. // Only objects that support object handles
  965. // can be guaranteed to be safe. Local variables are
  966. // already safe, so there is no need to add an extra
  967. // references
  968. if( !engine->ep.allowUnsafeReferences &&
  969. !ctx->type.isVariable &&
  970. ctx->type.dataType.IsObject() &&
  971. !ctx->type.dataType.IsObjectHandle() &&
  972. ctx->type.dataType.GetBehaviour()->addref &&
  973. ctx->type.dataType.GetBehaviour()->release )
  974. {
  975. // Store a handle to the object as local variable
  976. asSExprContext tmp(engine);
  977. asCDataType dt = ctx->type.dataType;
  978. dt.MakeHandle(true);
  979. dt.MakeReference(false);
  980. asCArray<int> vars;
  981. ctx->bc.GetVarsUsed(vars);
  982. if( reservedVars ) vars.Concatenate(*reservedVars);
  983. offset = AllocateVariableNotIn(dt, true, &vars);
  984. // Copy the handle
  985. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  986. ctx->bc.Instr(asBC_RDSPTR);
  987. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  988. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  989. ctx->bc.Pop(AS_PTR_SIZE);
  990. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  991. dt.MakeHandle(false);
  992. dt.MakeReference(true);
  993. // Release previous temporary variable stored in the context (if any)
  994. if( ctx->type.isTemporary )
  995. {
  996. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  997. }
  998. ctx->type.SetVariable(dt, offset, true);
  999. }
  1000. // Make sure the reference to the value is on the stack
  1001. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() )
  1002. Dereference(ctx, true);
  1003. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1004. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1005. else if( ctx->type.dataType.IsPrimitive() )
  1006. ctx->bc.Instr(asBC_PshRPtr);
  1007. }
  1008. }
  1009. else
  1010. {
  1011. ProcessPropertyGetAccessor(ctx, node);
  1012. if( dt.IsPrimitive() )
  1013. {
  1014. IsVariableInitialized(&ctx->type, node);
  1015. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1016. // Implicitly convert primitives to the parameter type
  1017. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1018. if( ctx->type.isVariable )
  1019. {
  1020. PushVariableOnStack(ctx, dt.IsReference());
  1021. }
  1022. else if( ctx->type.isConstant )
  1023. {
  1024. ConvertToVariable(ctx);
  1025. PushVariableOnStack(ctx, dt.IsReference());
  1026. }
  1027. }
  1028. else
  1029. {
  1030. IsVariableInitialized(&ctx->type, node);
  1031. // Implicitly convert primitives to the parameter type
  1032. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1033. // Was the conversion successful?
  1034. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1035. {
  1036. asCString str;
  1037. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1038. Error(str.AddressOf(), node);
  1039. ctx->type.Set(dt);
  1040. }
  1041. if( dt.IsObjectHandle() )
  1042. ctx->type.isExplicitHandle = true;
  1043. if( dt.IsObject() )
  1044. {
  1045. if( !dt.IsReference() )
  1046. {
  1047. // Objects passed by value must be placed in temporary variables
  1048. // so that they are guaranteed to not be referenced anywhere else.
  1049. // The object must also be allocated on the heap, as the memory will
  1050. // be deleted by in as_callfunc_xxx.
  1051. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1052. PrepareTemporaryObject(node, ctx, reservedVars, true);
  1053. // The implicit conversion shouldn't convert the object to
  1054. // non-reference yet. It will be dereferenced just before the call.
  1055. // Otherwise the object might be missed by the exception handler.
  1056. dt.MakeReference(true);
  1057. }
  1058. else
  1059. {
  1060. // An object passed by reference should place the pointer to
  1061. // the object on the stack.
  1062. dt.MakeReference(false);
  1063. }
  1064. }
  1065. }
  1066. }
  1067. // Don't put any pointer on the stack yet
  1068. if( param.IsReference() || param.IsObject() )
  1069. {
  1070. // &inout parameter may leave the reference on the stack already
  1071. if( refType != 3 )
  1072. {
  1073. ctx->bc.Pop(AS_PTR_SIZE);
  1074. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1075. }
  1076. ProcessDeferredParams(ctx);
  1077. }
  1078. }
  1079. void asCCompiler::PrepareFunctionCall(int funcID, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1080. {
  1081. // When a match has been found, compile the final byte code using correct parameter types
  1082. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  1083. // Add code for arguments
  1084. asSExprContext e(engine);
  1085. int n;
  1086. for( n = (int)args.GetLength()-1; n >= 0; n-- )
  1087. {
  1088. // Make sure PrepareArgument doesn't use any variable that is already
  1089. // being used by any of the following argument expressions
  1090. asCArray<int> reservedVars;
  1091. for( int m = n-1; m >= 0; m-- )
  1092. args[m]->bc.GetVarsUsed(reservedVars);
  1093. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], &reservedVars);
  1094. }
  1095. bc->AddCode(&e.bc);
  1096. }
  1097. void asCCompiler::MoveArgsToStack(int funcID, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1098. {
  1099. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  1100. int offset = 0;
  1101. if( addOneToOffset )
  1102. offset += AS_PTR_SIZE;
  1103. // Move the objects that are sent by value to the stack just before the call
  1104. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1105. {
  1106. if( descr->parameterTypes[n].IsReference() )
  1107. {
  1108. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1109. {
  1110. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1111. {
  1112. if( (args[n]->type.isVariable || args[n]->type.isTemporary) &&
  1113. !IsVariableOnHeap(args[n]->type.stackOffset) )
  1114. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1115. // as the value allocated on the stack is guaranteed to be safe
  1116. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1117. else
  1118. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1119. }
  1120. if( args[n]->type.dataType.IsObjectHandle() )
  1121. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1122. }
  1123. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1124. {
  1125. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1126. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1127. {
  1128. // Send the object as a reference to the object,
  1129. // and not to the variable holding the object
  1130. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1131. }
  1132. else
  1133. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1134. }
  1135. }
  1136. else if( descr->parameterTypes[n].IsObject() )
  1137. {
  1138. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1139. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1140. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1141. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1142. // The temporary variable must not be freed as it will no longer hold an object
  1143. DeallocateVariable(args[n]->type.stackOffset);
  1144. args[n]->type.isTemporary = false;
  1145. }
  1146. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1147. }
  1148. }
  1149. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1150. {
  1151. asASSERT(node->nodeType == snArgList);
  1152. // Count arguments
  1153. asCScriptNode *arg = node->firstChild;
  1154. int argCount = 0;
  1155. while( arg )
  1156. {
  1157. argCount++;
  1158. arg = arg->next;
  1159. }
  1160. // Prepare the arrays
  1161. args.SetLength(argCount);
  1162. int n;
  1163. for( n = 0; n < argCount; n++ )
  1164. args[n] = 0;
  1165. n = argCount-1;
  1166. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1167. bool anyErrors = false;
  1168. arg = node->lastChild;
  1169. while( arg )
  1170. {
  1171. asSExprContext expr(engine);
  1172. int r = CompileAssignment(arg, &expr);
  1173. if( r < 0 ) anyErrors = true;
  1174. args[n] = asNEW(asSExprContext)(engine);
  1175. MergeExprBytecodeAndType(args[n], &expr);
  1176. n--;
  1177. arg = arg->prev;
  1178. }
  1179. return anyErrors ? -1 : 0;
  1180. }
  1181. void asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1182. {
  1183. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1184. asUINT n;
  1185. if( funcs.GetLength() > 0 )
  1186. {
  1187. // Check the number of parameters in the found functions
  1188. for( n = 0; n < funcs.GetLength(); ++n )
  1189. {
  1190. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1191. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1192. {
  1193. // remove it from the list
  1194. if( n == funcs.GetLength()-1 )
  1195. funcs.PopLast();
  1196. else
  1197. funcs[n] = funcs.PopLast();
  1198. n--;
  1199. }
  1200. }
  1201. // Match functions with the parameters, and discard those that do not match
  1202. asCArray<int> matchingFuncs = funcs;
  1203. for( n = 0; n < args.GetLength(); ++n )
  1204. {
  1205. asCArray<int> tempFuncs;
  1206. MatchArgument(funcs, tempFuncs, &args[n]->type, n, allowObjectConstruct);
  1207. // Intersect the found functions with the list of matching functions
  1208. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1209. {
  1210. asUINT c;
  1211. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1212. {
  1213. if( matchingFuncs[f] == tempFuncs[c] )
  1214. break;
  1215. }
  1216. // Was the function a match?
  1217. if( c == tempFuncs.GetLength() )
  1218. {
  1219. // No, remove it from the list
  1220. if( f == matchingFuncs.GetLength()-1 )
  1221. matchingFuncs.PopLast();
  1222. else
  1223. matchingFuncs[f] = matchingFuncs.PopLast();
  1224. f--;
  1225. }
  1226. }
  1227. }
  1228. funcs = matchingFuncs;
  1229. }
  1230. if( !isConstMethod )
  1231. FilterConst(funcs);
  1232. if( funcs.GetLength() != 1 && !silent )
  1233. {
  1234. // Build a readable string of the function with parameter types
  1235. asCString str;
  1236. if( scope != "" )
  1237. {
  1238. if( scope == "::" )
  1239. str = scope;
  1240. else
  1241. str = scope + "::";
  1242. }
  1243. str += name;
  1244. str += "(";
  1245. if( args.GetLength() )
  1246. str += args[0]->type.dataType.Format();
  1247. for( n = 1; n < args.GetLength(); n++ )
  1248. str += ", " + args[n]->type.dataType.Format();
  1249. str += ")";
  1250. if( isConstMethod )
  1251. str += " const";
  1252. if( objectType && scope == "" )
  1253. str = objectType->name + "::" + str;
  1254. if( funcs.GetLength() == 0 )
  1255. {
  1256. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1257. Error(str.AddressOf(), node);
  1258. // Print the list of candidates
  1259. if( origFuncs.GetLength() > 0 )
  1260. {
  1261. int r = 0, c = 0;
  1262. asASSERT( node );
  1263. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1264. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1265. PrintMatchingFuncs(origFuncs, node);
  1266. }
  1267. }
  1268. else
  1269. {
  1270. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1271. Error(str.AddressOf(), node);
  1272. PrintMatchingFuncs(funcs, node);
  1273. }
  1274. }
  1275. }
  1276. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1277. {
  1278. // Get the data type
  1279. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script);
  1280. // Declare all variables in this declaration
  1281. asCScriptNode *node = decl->firstChild->next;
  1282. while( node )
  1283. {
  1284. // Is the type allowed?
  1285. if( !type.CanBeInstanciated() )
  1286. {
  1287. asCString str;
  1288. // TODO: Change to "'type' cannot be declared as variable"
  1289. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1290. Error(str.AddressOf(), node);
  1291. // Use int instead to avoid further problems
  1292. type = asCDataType::CreatePrimitive(ttInt, false);
  1293. }
  1294. // Get the name of the identifier
  1295. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1296. // Verify that the name isn't used by a dynamic data type
  1297. if( engine->GetObjectType(name.AddressOf()) != 0 )
  1298. {
  1299. asCString str;
  1300. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1301. Error(str.AddressOf(), node);
  1302. }
  1303. int offset = AllocateVariable(type, false);
  1304. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1305. {
  1306. asCString str;
  1307. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1308. Error(str.AddressOf(), node);
  1309. // Don't continue after this error, as it will just
  1310. // lead to more errors that are likely false
  1311. return;
  1312. }
  1313. outFunc->AddVariable(name, type, offset);
  1314. // Keep the node for the variable decl
  1315. asCScriptNode *varNode = node;
  1316. node = node->next;
  1317. if( node && node->nodeType == snArgList )
  1318. {
  1319. // Make sure that it is a registered type, and that is isn't a pointer
  1320. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1321. {
  1322. Error(TXT_MUST_BE_OBJECT, node);
  1323. }
  1324. else
  1325. {
  1326. // Compile the arguments
  1327. asCArray<asSExprContext *> args;
  1328. if( CompileArgumentList(node, args) >= 0 )
  1329. {
  1330. // Find all constructors
  1331. asCArray<int> funcs;
  1332. asSTypeBehaviour *beh = type.GetBehaviour();
  1333. if( beh )
  1334. {
  1335. if( type.GetObjectType()->flags & asOBJ_REF )
  1336. funcs = beh->factories;
  1337. else
  1338. funcs = beh->constructors;
  1339. }
  1340. asCString str = type.Format();
  1341. MatchFunctions(funcs, args, node, str.AddressOf());
  1342. if( funcs.GetLength() == 1 )
  1343. {
  1344. sVariable *v = variables->GetVariable(name.AddressOf());
  1345. asSExprContext ctx(engine);
  1346. if( v->type.GetObjectType() && (v->type.GetObjectType()->flags & asOBJ_REF) )
  1347. {
  1348. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
  1349. // Pop the reference left by the function call
  1350. ctx.bc.Pop(AS_PTR_SIZE);
  1351. }
  1352. else
  1353. {
  1354. // When the object is allocated on the heap, the address where the
  1355. // reference will be stored must be pushed on the stack before the
  1356. // arguments. This reference on the stack is safe, even if the script
  1357. // is suspended during the evaluation of the arguments.
  1358. if( v->onHeap )
  1359. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1360. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1361. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1362. // When the object is allocated on the stack, the address to the
  1363. // object is pushed on the stack after the arguments as the object pointer
  1364. if( !v->onHeap )
  1365. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1366. PerformFunctionCall(funcs[0], &ctx, v->onHeap, &args, type.GetObjectType());
  1367. // TODO: value on stack: This probably has to be done in PerformFunctionCall
  1368. // Mark the object as initialized
  1369. ctx.bc.ObjInfo(v->stackOffset, asOBJ_INIT);
  1370. }
  1371. bc->AddCode(&ctx.bc);
  1372. }
  1373. }
  1374. // Cleanup
  1375. for( asUINT n = 0; n < args.GetLength(); n++ )
  1376. if( args[n] )
  1377. {
  1378. asDELETE(args[n],asSExprContext);
  1379. }
  1380. }
  1381. node = node->next;
  1382. }
  1383. else if( node && node->nodeType == snInitList )
  1384. {
  1385. sVariable *v = variables->GetVariable(name.AddressOf());
  1386. asCTypeInfo ti;
  1387. ti.Set(type);
  1388. ti.isVariable = true;
  1389. ti.isTemporary = false;
  1390. ti.stackOffset = (short)v->stackOffset;
  1391. CompileInitList(&ti, node, bc);
  1392. node = node->next;
  1393. }
  1394. else if( node && node->nodeType == snAssignment )
  1395. {
  1396. asSExprContext ctx(engine);
  1397. // TODO: copy: Here we should look for the best matching constructor, instead of
  1398. // just the copy constructor. Only if no appropriate constructor is
  1399. // available should the assignment operator be used.
  1400. // Call the default constructor here
  1401. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, varNode);
  1402. // Compile the expression
  1403. asSExprContext expr(engine);
  1404. int r = CompileAssignment(node, &expr);
  1405. if( r >= 0 )
  1406. {
  1407. if( type.IsPrimitive() )
  1408. {
  1409. if( type.IsReadOnly() && expr.type.isConstant )
  1410. {
  1411. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1412. sVariable *v = variables->GetVariable(name.AddressOf());
  1413. v->isPureConstant = true;
  1414. v->constantValue = expr.type.qwordValue;
  1415. }
  1416. asSExprContext lctx(engine);
  1417. lctx.type.SetVariable(type, offset, false);
  1418. lctx.type.dataType.MakeReadOnly(false);
  1419. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1420. ProcessDeferredParams(&ctx);
  1421. }
  1422. else
  1423. {
  1424. // TODO: We can use a copy constructor here
  1425. sVariable *v = variables->GetVariable(name.AddressOf());
  1426. asSExprContext lexpr(engine);
  1427. lexpr.type.Set(type);
  1428. lexpr.type.dataType.MakeReference(v->onHeap);
  1429. // Allow initialization of constant variables
  1430. lexpr.type.dataType.MakeReadOnly(false);
  1431. if( type.IsObjectHandle() )
  1432. lexpr.type.isExplicitHandle = true;
  1433. lexpr.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1434. lexpr.type.stackOffset = (short)v->stackOffset;
  1435. lexpr.type.isVariable = true;
  1436. // If left expression resolves into a registered type
  1437. // check if the assignment operator is overloaded, and check
  1438. // the type of the right hand expression. If none is found
  1439. // the default action is a direct copy if it is the same type
  1440. // and a simple assignment.
  1441. bool assigned = false;
  1442. if( lexpr.type.dataType.IsObject() && !lexpr.type.isExplicitHandle )
  1443. {
  1444. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1445. if( assigned )
  1446. {
  1447. // Pop the resulting value
  1448. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  1449. // Release the argument
  1450. ProcessDeferredParams(&ctx);
  1451. // Release temporary variable that may be allocated by the overloaded operator
  1452. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1453. }
  1454. }
  1455. if( !assigned )
  1456. {
  1457. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  1458. // If the expression is constant and the variable also is constant
  1459. // then mark the variable as pure constant. This will allow the compiler
  1460. // to optimize expressions with this variable.
  1461. if( v->type.IsReadOnly() && expr.type.isConstant )
  1462. {
  1463. v->isPureConstant = true;
  1464. v->constantValue = expr.type.qwordValue;
  1465. }
  1466. // Add expression code to bytecode
  1467. MergeExprBytecode(&ctx, &expr);
  1468. // Add byte code for storing value of expression in variable
  1469. ctx.bc.AddCode(&lexpr.bc);
  1470. lexpr.type.stackOffset = (short)v->stackOffset;
  1471. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node->prev);
  1472. // Release temporary variables used by expression
  1473. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  1474. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  1475. ProcessDeferredParams(&ctx);
  1476. }
  1477. }
  1478. }
  1479. node = node->next;
  1480. bc->AddCode(&ctx.bc);
  1481. // TODO: Can't this leave deferred output params without being compiled?
  1482. }
  1483. else
  1484. {
  1485. // Call the default constructor here if no explicit initialization is done
  1486. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, varNode);
  1487. }
  1488. }
  1489. }
  1490. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc)
  1491. {
  1492. // Check if the type supports initialization lists
  1493. if( var->dataType.GetObjectType() == 0 ||
  1494. var->dataType.GetBehaviour()->listFactory == 0 ||
  1495. var->dataType.IsObjectHandle() )
  1496. {
  1497. asCString str;
  1498. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  1499. Error(str.AddressOf(), node);
  1500. return;
  1501. }
  1502. // Count the number of elements and initialize the array with the correct size
  1503. int countElements = 0;
  1504. asCScriptNode *el = node->firstChild;
  1505. while( el )
  1506. {
  1507. countElements++;
  1508. el = el->next;
  1509. }
  1510. // Construct the array with the size elements
  1511. // TODO: value on stack: This needs to support value types on the stack as well
  1512. // Find the list factory
  1513. // TODO: initlist: Add support for value types as well
  1514. int funcId = var->dataType.GetBehaviour()->listFactory;
  1515. asCArray<asSExprContext *> args;
  1516. asSExprContext arg1(engine);
  1517. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  1518. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  1519. args.PushLast(&arg1);
  1520. asSExprContext ctx(engine);
  1521. PrepareFunctionCall(funcId, &ctx.bc, args);
  1522. MoveArgsToStack(funcId, &ctx.bc, args, false);
  1523. if( var->isVariable )
  1524. {
  1525. // Call factory and store the handle in the given variable
  1526. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  1527. ctx.bc.Pop(AS_PTR_SIZE);
  1528. }
  1529. else
  1530. {
  1531. PerformFunctionCall(funcId, &ctx, false, &args);
  1532. // Store the returned handle in the global variable
  1533. ctx.bc.Instr(asBC_RDSPTR);
  1534. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1535. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  1536. ctx.bc.Pop(AS_PTR_SIZE);
  1537. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1538. }
  1539. bc->AddCode(&ctx.bc);
  1540. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  1541. // initialization lists with different types for different elements? Maybe
  1542. // by using the variable arguments the initialization can be done with one
  1543. // call, passing all the elements as arguments. The registered function can
  1544. // then traverse them however it wants.
  1545. // Find the indexing operator that is not read-only that will be used for all elements
  1546. asCDataType retType;
  1547. retType = var->dataType.GetSubType();
  1548. retType.MakeReference(true);
  1549. retType.MakeReadOnly(false);
  1550. funcId = 0;
  1551. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  1552. {
  1553. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  1554. if( !desc->isReadOnly &&
  1555. desc->parameterTypes.GetLength() == 1 &&
  1556. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1557. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1558. desc->returnType == retType &&
  1559. desc->name == "opIndex" )
  1560. {
  1561. funcId = var->dataType.GetObjectType()->methods[n];
  1562. break;
  1563. }
  1564. }
  1565. #ifdef AS_DEPRECATED
  1566. // Since 2.20.0
  1567. if( funcId == 0 )
  1568. {
  1569. asSTypeBehaviour *beh = var->dataType.GetBehaviour();
  1570. for( asUINT n = 0; n < beh->operators.GetLength(); n += 2 )
  1571. {
  1572. if( asBEHAVE_INDEX == beh->operators[n] )
  1573. {
  1574. asCScriptFunction *desc = builder->GetFunctionDescription(beh->operators[n+1]);
  1575. if( !desc->isReadOnly &&
  1576. desc->parameterTypes.GetLength() == 1 &&
  1577. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1578. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1579. desc->returnType == retType )
  1580. {
  1581. funcId = beh->operators[n+1];
  1582. break;
  1583. }
  1584. }
  1585. }
  1586. }
  1587. #endif
  1588. if( funcId == 0 )
  1589. {
  1590. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  1591. return;
  1592. }
  1593. asUINT index = 0;
  1594. el = node->firstChild;
  1595. while( el )
  1596. {
  1597. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  1598. {
  1599. asSExprContext lctx(engine);
  1600. asSExprContext rctx(engine);
  1601. if( el->nodeType == snAssignment )
  1602. {
  1603. // Compile the assignment expression
  1604. CompileAssignment(el, &rctx);
  1605. }
  1606. else if( el->nodeType == snInitList )
  1607. {
  1608. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  1609. rctx.type.Set(var->dataType.GetSubType());
  1610. rctx.type.isVariable = true;
  1611. rctx.type.isTemporary = true;
  1612. rctx.type.stackOffset = (short)offset;
  1613. CompileInitList(&rctx.type, el, &rctx.bc);
  1614. // Put the object on the stack
  1615. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  1616. // It is a reference that we place on the stack
  1617. rctx.type.dataType.MakeReference(true);
  1618. }
  1619. // Compile the lvalue
  1620. lctx.bc.InstrDWORD(asBC_PshC4, index);
  1621. if( var->isVariable )
  1622. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  1623. else
  1624. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1625. lctx.bc.Instr(asBC_RDSPTR);
  1626. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  1627. if( !var->dataType.GetSubType().IsPrimitive() )
  1628. lctx.bc.Instr(asBC_PshRPtr);
  1629. lctx.type.Set(var->dataType.GetSubType());
  1630. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  1631. lctx.type.dataType.MakeReference(true);
  1632. // If the element type is handles, then we're expected to do handle assignments
  1633. if( lctx.type.dataType.IsObjectHandle() )
  1634. lctx.type.isExplicitHandle = true;
  1635. asSExprContext ctx(engine);
  1636. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  1637. if( !lctx.type.dataType.IsPrimitive() )
  1638. ctx.bc.Pop(AS_PTR_SIZE);
  1639. // Release temporary variables used by expression
  1640. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1641. ProcessDeferredParams(&ctx);
  1642. bc->AddCode(&ctx.bc);
  1643. }
  1644. el = el->next;
  1645. index++;
  1646. }
  1647. }
  1648. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  1649. {
  1650. *hasReturn = false;
  1651. if( statement->nodeType == snStatementBlock )
  1652. CompileStatementBlock(statement, true, hasReturn, bc);
  1653. else if( statement->nodeType == snIf )
  1654. CompileIfStatement(statement, hasReturn, bc);
  1655. else if( statement->nodeType == snFor )
  1656. CompileForStatement(statement, bc);
  1657. else if( statement->nodeType == snWhile )
  1658. CompileWhileStatement(statement, bc);
  1659. else if( statement->nodeType == snDoWhile )
  1660. CompileDoWhileStatement(statement, bc);
  1661. else if( statement->nodeType == snExpressionStatement )
  1662. CompileExpressionStatement(statement, bc);
  1663. else if( statement->nodeType == snBreak )
  1664. CompileBreakStatement(statement, bc);
  1665. else if( statement->nodeType == snContinue )
  1666. CompileContinueStatement(statement, bc);
  1667. else if( statement->nodeType == snSwitch )
  1668. CompileSwitchStatement(statement, hasReturn, bc);
  1669. else if( statement->nodeType == snReturn )
  1670. {
  1671. CompileReturnStatement(statement, bc);
  1672. *hasReturn = true;
  1673. }
  1674. }
  1675. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  1676. {
  1677. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  1678. // Reserve label for break statements
  1679. int breakLabel = nextLabel++;
  1680. breakLabels.PushLast(breakLabel);
  1681. // Add a variable scope that will be used by CompileBreak
  1682. // to know where to stop deallocating variables
  1683. AddVariableScope(true, false);
  1684. //---------------------------
  1685. // Compile the switch expression
  1686. //-------------------------------
  1687. // Compile the switch expression
  1688. asSExprContext expr(engine);
  1689. CompileAssignment(snode->firstChild, &expr);
  1690. // Verify that the expression is a primitive type
  1691. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
  1692. {
  1693. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  1694. return;
  1695. }
  1696. ProcessPropertyGetAccessor(&expr, snode);
  1697. // TODO: Need to support 64bit integers
  1698. // Convert the expression to a 32bit variable
  1699. asCDataType to;
  1700. if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
  1701. to.SetTokenType(ttInt);
  1702. else if( expr.type.dataType.IsUnsignedType() )
  1703. to.SetTokenType(ttUInt);
  1704. // Make sure the value is in a variable
  1705. if( expr.type.dataType.IsReference() )
  1706. ConvertToVariable(&expr);
  1707. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  1708. ConvertToVariable(&expr);
  1709. int offset = expr.type.stackOffset;
  1710. ProcessDeferredParams(&expr);
  1711. //-------------------------------
  1712. // Determine case values and labels
  1713. //--------------------------------
  1714. // Remember the first label so that we can later pass the
  1715. // correct label to each CompileCase()
  1716. int firstCaseLabel = nextLabel;
  1717. int defaultLabel = 0;
  1718. asCArray<int> caseValues;
  1719. asCArray<int> caseLabels;
  1720. // Compile all case comparisons and make them jump to the right label
  1721. asCScriptNode *cnode = snode->firstChild->next;
  1722. while( cnode )
  1723. {
  1724. // Each case should have a constant expression
  1725. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1726. {
  1727. // Compile expression
  1728. asSExprContext c(engine);
  1729. CompileExpression(cnode->firstChild, &c);
  1730. // Verify that the result is a constant
  1731. if( !c.type.isConstant )
  1732. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  1733. // Verify that the result is an integral number
  1734. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
  1735. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  1736. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  1737. // Has this case been declared already?
  1738. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  1739. {
  1740. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  1741. }
  1742. // TODO: Optimize: We can insert the numbers sorted already
  1743. // Store constant for later use
  1744. caseValues.PushLast(c.type.intValue);
  1745. // Reserve label for this case
  1746. caseLabels.PushLast(nextLabel++);
  1747. }
  1748. else
  1749. {
  1750. // Is default the last case?
  1751. if( cnode->next )
  1752. {
  1753. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  1754. break;
  1755. }
  1756. // Reserve label for this case
  1757. defaultLabel = nextLabel++;
  1758. }
  1759. cnode = cnode->next;
  1760. }
  1761. // check for empty switch
  1762. if (caseValues.GetLength() == 0)
  1763. {
  1764. Error(TXT_EMPTY_SWITCH, snode);
  1765. return;
  1766. }
  1767. if( defaultLabel == 0 )
  1768. defaultLabel = breakLabel;
  1769. //---------------------------------
  1770. // Output the optimized case comparisons
  1771. // with jumps to the case code
  1772. //------------------------------------
  1773. // Sort the case values by increasing value. Do the sort together with the labels
  1774. // A simple bubble sort is sufficient since we don't expect a huge number of values
  1775. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  1776. {
  1777. for( int bck = fwd - 1; bck >= 0; bck-- )
  1778. {
  1779. int bckp = bck + 1;
  1780. if( caseValues[bck] > caseValues[bckp] )
  1781. {
  1782. // Swap the values in both arrays
  1783. int swap = caseValues[bckp];
  1784. caseValues[bckp] = caseValues[bck];
  1785. caseValues[bck] = swap;
  1786. swap = caseLabels[bckp];
  1787. caseLabels[bckp] = caseLabels[bck];
  1788. caseLabels[bck] = swap;
  1789. }
  1790. else
  1791. break;
  1792. }
  1793. }
  1794. // Find ranges of consecutive numbers
  1795. asCArray<int> ranges;
  1796. ranges.PushLast(0);
  1797. asUINT n;
  1798. for( n = 1; n < caseValues.GetLength(); ++n )
  1799. {
  1800. // We can join numbers that are less than 5 numbers
  1801. // apart since the output code will still be smaller
  1802. if( caseValues[n] > caseValues[n-1] + 5 )
  1803. ranges.PushLast(n);
  1804. }
  1805. // If the value is larger than the largest case value, jump to default
  1806. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1807. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  1808. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1809. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  1810. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1811. // TODO: optimize: We could possibly optimize this even more by doing a
  1812. // binary search instead of a linear search through the ranges
  1813. // For each range
  1814. int range;
  1815. for( range = 0; range < (int)ranges.GetLength(); range++ )
  1816. {
  1817. // Find the largest value in this range
  1818. int maxRange = caseValues[ranges[range]];
  1819. int index = ranges[range];
  1820. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  1821. maxRange = caseValues[index];
  1822. // If there are only 2 numbers then it is better to compare them directly
  1823. if( index - ranges[range] > 2 )
  1824. {
  1825. // If the value is smaller than the smallest case value in the range, jump to default
  1826. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1827. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1828. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1829. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  1830. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1831. int nextRangeLabel = nextLabel++;
  1832. // If this is the last range we don't have to make this test
  1833. if( range < (int)ranges.GetLength() - 1 )
  1834. {
  1835. // If the value is larger than the largest case value in the range, jump to the next range
  1836. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1837. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  1838. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1839. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  1840. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1841. }
  1842. // Jump forward according to the value
  1843. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1844. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1845. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  1846. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1847. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  1848. // Add the list of jumps to the correct labels (any holes, jump to default)
  1849. index = ranges[range];
  1850. for( int n = caseValues[index]; n <= maxRange; n++ )
  1851. {
  1852. if( caseValues[index] == n )
  1853. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  1854. else
  1855. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  1856. }
  1857. expr.bc.Label((short)nextRangeLabel);
  1858. }
  1859. else
  1860. {
  1861. // Simply make a comparison with each value
  1862. int n;
  1863. for( n = ranges[range]; n < index; ++n )
  1864. {
  1865. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1866. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  1867. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1868. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  1869. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1870. }
  1871. }
  1872. }
  1873. // Catch any value that falls trough
  1874. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  1875. // Release the temporary variable previously stored
  1876. ReleaseTemporaryVariable(expr.type, &expr.bc);
  1877. //----------------------------------
  1878. // Output case implementations
  1879. //----------------------------------
  1880. // Compile case implementations, each one with the label before it
  1881. cnode = snode->firstChild->next;
  1882. while( cnode )
  1883. {
  1884. // Each case should have a constant expression
  1885. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1886. {
  1887. expr.bc.Label((short)firstCaseLabel++);
  1888. CompileCase(cnode->firstChild->next, &expr.bc);
  1889. }
  1890. else
  1891. {
  1892. expr.bc.Label((short)defaultLabel);
  1893. // Is default the last case?
  1894. if( cnode->next )
  1895. {
  1896. // We've already reported this error
  1897. break;
  1898. }
  1899. CompileCase(cnode->firstChild, &expr.bc);
  1900. }
  1901. cnode = cnode->next;
  1902. }
  1903. //--------------------------------
  1904. bc->AddCode(&expr.bc);
  1905. // Add break label
  1906. bc->Label((short)breakLabel);
  1907. breakLabels.PopLast();
  1908. RemoveVariableScope();
  1909. }
  1910. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  1911. {
  1912. bool isFinished = false;
  1913. bool hasReturn = false;
  1914. while( node )
  1915. {
  1916. if( hasReturn || isFinished )
  1917. {
  1918. Warning(TXT_UNREACHABLE_CODE, node);
  1919. break;
  1920. }
  1921. if( node->nodeType == snBreak || node->nodeType == snContinue )
  1922. isFinished = true;
  1923. asCByteCode statement(engine);
  1924. if( node->nodeType == snDeclaration )
  1925. {
  1926. Error(TXT_DECL_IN_SWITCH, node);
  1927. // Compile it anyway to avoid further compiler errors
  1928. CompileDeclaration(node, &statement);
  1929. }
  1930. else
  1931. CompileStatement(node, &hasReturn, &statement);
  1932. LineInstr(bc, node->tokenPos);
  1933. bc->AddCode(&statement);
  1934. if( !hasCompileErrors )
  1935. asASSERT( tempVariables.GetLength() == 0 );
  1936. node = node->next;
  1937. }
  1938. }
  1939. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  1940. {
  1941. // We will use one label for the if statement
  1942. // and possibly another for the else statement
  1943. int afterLabel = nextLabel++;
  1944. // Compile the expression
  1945. asSExprContext expr(engine);
  1946. CompileAssignment(inode->firstChild, &expr);
  1947. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  1948. {
  1949. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  1950. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  1951. }
  1952. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  1953. ProcessDeferredParams(&expr);
  1954. if( !expr.type.isConstant )
  1955. {
  1956. ProcessPropertyGetAccessor(&expr, inode);
  1957. ConvertToVariable(&expr);
  1958. // Add byte code from the expression
  1959. bc->AddCode(&expr.bc);
  1960. // Add a test
  1961. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  1962. bc->Instr(asBC_ClrHi);
  1963. bc->InstrDWORD(asBC_JZ, afterLabel);
  1964. ReleaseTemporaryVariable(expr.type, bc);
  1965. }
  1966. else if( expr.type.dwordValue == 0 )
  1967. {
  1968. // Jump to the else case
  1969. bc->InstrINT(asBC_JMP, afterLabel);
  1970. // TODO: Should we warn that the expression will always go to the else?
  1971. }
  1972. // Compile the if statement
  1973. bool origIsConstructorCalled = m_isConstructorCalled;
  1974. bool hasReturn1;
  1975. asCByteCode ifBC(engine);
  1976. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  1977. // Add the byte code
  1978. LineInstr(bc, inode->firstChild->next->tokenPos);
  1979. bc->AddCode(&ifBC);
  1980. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  1981. {
  1982. // Don't allow if( expr );
  1983. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  1984. }
  1985. // If one of the statements call the constructor, the other must as well
  1986. // otherwise it is possible the constructor is never called
  1987. bool constructorCall1 = false;
  1988. bool constructorCall2 = false;
  1989. if( !origIsConstructorCalled && m_isConstructorCalled )
  1990. constructorCall1 = true;
  1991. // Do we have an else statement?
  1992. if( inode->firstChild->next != inode->lastChild )
  1993. {
  1994. // Reset the constructor called flag so the else statement can call the constructor too
  1995. m_isConstructorCalled = origIsConstructorCalled;
  1996. int afterElse = 0;
  1997. if( !hasReturn1 )
  1998. {
  1999. afterElse = nextLabel++;
  2000. // Add jump to after the else statement
  2001. bc->InstrINT(asBC_JMP, afterElse);
  2002. }
  2003. // Add label for the else statement
  2004. bc->Label((short)afterLabel);
  2005. bool hasReturn2;
  2006. asCByteCode elseBC(engine);
  2007. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2008. // Add byte code for the else statement
  2009. LineInstr(bc, inode->lastChild->tokenPos);
  2010. bc->AddCode(&elseBC);
  2011. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2012. {
  2013. // Don't allow if( expr ) {} else;
  2014. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2015. }
  2016. if( !hasReturn1 )
  2017. {
  2018. // Add label for the end of else statement
  2019. bc->Label((short)afterElse);
  2020. }
  2021. // The if statement only has return if both alternatives have
  2022. *hasReturn = hasReturn1 && hasReturn2;
  2023. if( !origIsConstructorCalled && m_isConstructorCalled )
  2024. constructorCall2 = true;
  2025. }
  2026. else
  2027. {
  2028. // Add label for the end of if statement
  2029. bc->Label((short)afterLabel);
  2030. *hasReturn = false;
  2031. }
  2032. // Make sure both or neither conditions call a constructor
  2033. if( (constructorCall1 && !constructorCall2) ||
  2034. (constructorCall2 && !constructorCall1) )
  2035. {
  2036. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2037. }
  2038. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2039. }
  2040. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2041. {
  2042. // TODO: optimize: We should be able to remove the static JMP to the beginning of the loop by rearranging the
  2043. // byte code a bit.
  2044. //
  2045. // init
  2046. // jump to before
  2047. // begin:
  2048. // statements
  2049. // continue:
  2050. // next
  2051. // before:
  2052. // condition
  2053. // if loop jump to begin
  2054. // break:
  2055. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2056. AddVariableScope(true, true);
  2057. // We will use three labels for the for loop
  2058. int beforeLabel = nextLabel++;
  2059. int afterLabel = nextLabel++;
  2060. int continueLabel = nextLabel++;
  2061. continueLabels.PushLast(continueLabel);
  2062. breakLabels.PushLast(afterLabel);
  2063. //---------------------------------------
  2064. // Compile the initialization statement
  2065. asCByteCode initBC(engine);
  2066. if( fnode->firstChild->nodeType == snDeclaration )
  2067. CompileDeclaration(fnode->firstChild, &initBC);
  2068. else
  2069. CompileExpressionStatement(fnode->firstChild, &initBC);
  2070. //-----------------------------------
  2071. // Compile the condition statement
  2072. asSExprContext expr(engine);
  2073. asCScriptNode *second = fnode->firstChild->next;
  2074. if( second->firstChild )
  2075. {
  2076. int r = CompileAssignment(second->firstChild, &expr);
  2077. if( r >= 0 )
  2078. {
  2079. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2080. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2081. else
  2082. {
  2083. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2084. ProcessDeferredParams(&expr);
  2085. ProcessPropertyGetAccessor(&expr, second);
  2086. // If expression is false exit the loop
  2087. ConvertToVariable(&expr);
  2088. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2089. expr.bc.Instr(asBC_ClrHi);
  2090. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2091. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2092. }
  2093. }
  2094. }
  2095. //---------------------------
  2096. // Compile the increment statement
  2097. asCByteCode nextBC(engine);
  2098. asCScriptNode *third = second->next;
  2099. if( third->nodeType == snExpressionStatement )
  2100. CompileExpressionStatement(third, &nextBC);
  2101. //------------------------------
  2102. // Compile loop statement
  2103. bool hasReturn;
  2104. asCByteCode forBC(engine);
  2105. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2106. //-------------------------------
  2107. // Join the code pieces
  2108. bc->AddCode(&initBC);
  2109. bc->Label((short)beforeLabel);
  2110. // Add a suspend bytecode inside the loop to guarantee
  2111. // that the application can suspend the execution
  2112. bc->Instr(asBC_SUSPEND);
  2113. bc->InstrWORD(asBC_JitEntry, 0);
  2114. bc->AddCode(&expr.bc);
  2115. LineInstr(bc, fnode->lastChild->tokenPos);
  2116. bc->AddCode(&forBC);
  2117. bc->Label((short)continueLabel);
  2118. bc->AddCode(&nextBC);
  2119. bc->InstrINT(asBC_JMP, beforeLabel);
  2120. bc->Label((short)afterLabel);
  2121. continueLabels.PopLast();
  2122. breakLabels.PopLast();
  2123. // Deallocate variables in this block, in reverse order
  2124. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2125. {
  2126. sVariable *v = variables->variables[n];
  2127. // Call variable destructors here, for variables not yet destroyed
  2128. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2129. // Don't deallocate function parameters
  2130. if( v->stackOffset > 0 )
  2131. DeallocateVariable(v->stackOffset);
  2132. }
  2133. RemoveVariableScope();
  2134. }
  2135. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2136. {
  2137. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2138. AddVariableScope(true, true);
  2139. // We will use two labels for the while loop
  2140. int beforeLabel = nextLabel++;
  2141. int afterLabel = nextLabel++;
  2142. continueLabels.PushLast(beforeLabel);
  2143. breakLabels.PushLast(afterLabel);
  2144. // Add label before the expression
  2145. bc->Label((short)beforeLabel);
  2146. // Compile expression
  2147. asSExprContext expr(engine);
  2148. CompileAssignment(wnode->firstChild, &expr);
  2149. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2150. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2151. else
  2152. {
  2153. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2154. ProcessDeferredParams(&expr);
  2155. ProcessPropertyGetAccessor(&expr, wnode);
  2156. // Add byte code for the expression
  2157. ConvertToVariable(&expr);
  2158. bc->AddCode(&expr.bc);
  2159. // Jump to end of statement if expression is false
  2160. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2161. bc->Instr(asBC_ClrHi);
  2162. bc->InstrDWORD(asBC_JZ, afterLabel);
  2163. ReleaseTemporaryVariable(expr.type, bc);
  2164. }
  2165. // Add a suspend bytecode inside the loop to guarantee
  2166. // that the application can suspend the execution
  2167. bc->Instr(asBC_SUSPEND);
  2168. bc->InstrWORD(asBC_JitEntry, 0);
  2169. // Compile statement
  2170. bool hasReturn;
  2171. asCByteCode whileBC(engine);
  2172. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2173. // Add byte code for the statement
  2174. LineInstr(bc, wnode->lastChild->tokenPos);
  2175. bc->AddCode(&whileBC);
  2176. // Jump to the expression
  2177. bc->InstrINT(asBC_JMP, beforeLabel);
  2178. // Add label after the statement
  2179. bc->Label((short)afterLabel);
  2180. continueLabels.PopLast();
  2181. breakLabels.PopLast();
  2182. RemoveVariableScope();
  2183. }
  2184. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2185. {
  2186. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2187. AddVariableScope(true, true);
  2188. // We will use two labels for the while loop
  2189. int beforeLabel = nextLabel++;
  2190. int beforeTest = nextLabel++;
  2191. int afterLabel = nextLabel++;
  2192. continueLabels.PushLast(beforeTest);
  2193. breakLabels.PushLast(afterLabel);
  2194. // Add label before the statement
  2195. bc->Label((short)beforeLabel);
  2196. // Compile statement
  2197. bool hasReturn;
  2198. asCByteCode whileBC(engine);
  2199. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2200. // Add byte code for the statement
  2201. LineInstr(bc, wnode->firstChild->tokenPos);
  2202. bc->AddCode(&whileBC);
  2203. // Add label before the expression
  2204. bc->Label((short)beforeTest);
  2205. // Add a suspend bytecode inside the loop to guarantee
  2206. // that the application can suspend the execution
  2207. bc->Instr(asBC_SUSPEND);
  2208. bc->InstrWORD(asBC_JitEntry, 0);
  2209. // Add a line instruction
  2210. LineInstr(bc, wnode->lastChild->tokenPos);
  2211. // Compile expression
  2212. asSExprContext expr(engine);
  2213. CompileAssignment(wnode->lastChild, &expr);
  2214. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2215. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2216. else
  2217. {
  2218. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2219. ProcessDeferredParams(&expr);
  2220. ProcessPropertyGetAccessor(&expr, wnode);
  2221. // Add byte code for the expression
  2222. ConvertToVariable(&expr);
  2223. bc->AddCode(&expr.bc);
  2224. // Jump to next iteration if expression is true
  2225. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2226. bc->Instr(asBC_ClrHi);
  2227. bc->InstrDWORD(asBC_JNZ, beforeLabel);
  2228. ReleaseTemporaryVariable(expr.type, bc);
  2229. }
  2230. // Add label after the statement
  2231. bc->Label((short)afterLabel);
  2232. continueLabels.PopLast();
  2233. breakLabels.PopLast();
  2234. RemoveVariableScope();
  2235. }
  2236. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2237. {
  2238. if( breakLabels.GetLength() == 0 )
  2239. {
  2240. Error(TXT_INVALID_BREAK, node);
  2241. return;
  2242. }
  2243. // Add destructor calls for all variables that will go out of scope
  2244. // Put this clean up in a block to allow exception handler to understand them
  2245. bc->Block(true);
  2246. asCVariableScope *vs = variables;
  2247. while( !vs->isBreakScope )
  2248. {
  2249. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2250. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2251. vs = vs->parent;
  2252. }
  2253. bc->Block(false);
  2254. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2255. }
  2256. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2257. {
  2258. if( continueLabels.GetLength() == 0 )
  2259. {
  2260. Error(TXT_INVALID_CONTINUE, node);
  2261. return;
  2262. }
  2263. // Add destructor calls for all variables that will go out of scope
  2264. // Put this clean up in a block to allow exception handler to understand them
  2265. bc->Block(true);
  2266. asCVariableScope *vs = variables;
  2267. while( !vs->isContinueScope )
  2268. {
  2269. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2270. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2271. vs = vs->parent;
  2272. }
  2273. bc->Block(false);
  2274. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2275. }
  2276. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2277. {
  2278. if( enode->firstChild )
  2279. {
  2280. // Compile the expression
  2281. asSExprContext expr(engine);
  2282. CompileAssignment(enode->firstChild, &expr);
  2283. // Pop the value from the stack
  2284. if( !expr.type.dataType.IsPrimitive() )
  2285. expr.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  2286. // Release temporary variables used by expression
  2287. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2288. ProcessDeferredParams(&expr);
  2289. bc->AddCode(&expr.bc);
  2290. }
  2291. }
  2292. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, asCArray<int> *reservedVars, bool forceOnHeap)
  2293. {
  2294. // If the object already is stored in temporary variable then nothing needs to be done
  2295. // Note, a type can be temporary without being a variable, in which case it is holding off
  2296. // on releasing a previously used object.
  2297. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2298. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2299. {
  2300. // If the temporary object is currently not a reference
  2301. // the expression needs to be reevaluated to a reference
  2302. if( !ctx->type.dataType.IsReference() )
  2303. {
  2304. ctx->bc.Pop(AS_PTR_SIZE);
  2305. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2306. ctx->type.dataType.MakeReference(true);
  2307. }
  2308. return;
  2309. }
  2310. // Allocate temporary variable
  2311. asCDataType dt = ctx->type.dataType;
  2312. dt.MakeReference(false);
  2313. dt.MakeReadOnly(false);
  2314. int offset = AllocateVariableNotIn(dt, true, reservedVars, forceOnHeap);
  2315. // Objects stored on the stack are not considered references
  2316. dt.MakeReference(IsVariableOnHeap(offset));
  2317. asCTypeInfo lvalue;
  2318. lvalue.Set(dt);
  2319. lvalue.isTemporary = true;
  2320. lvalue.stackOffset = (short)offset;
  2321. lvalue.isVariable = true;
  2322. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2323. if( !dt.IsObjectHandle() && dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2324. {
  2325. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2326. // Use the copy constructor/factory when available
  2327. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2328. }
  2329. else
  2330. {
  2331. // Allocate and construct the temporary object
  2332. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2333. // Assign the object to the temporary variable
  2334. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2335. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2336. PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2337. // Pop the original reference
  2338. ctx->bc.Pop(AS_PTR_SIZE);
  2339. }
  2340. // If the expression was holding off on releasing a
  2341. // previously used object, we need to release it now
  2342. if( ctx->type.isTemporary )
  2343. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2344. // Push the reference to the temporary variable on the stack
  2345. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2346. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2347. ctx->type = lvalue;
  2348. }
  2349. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2350. {
  2351. // Get return type and location
  2352. sVariable *v = variables->GetVariable("return");
  2353. // Basic validations
  2354. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2355. {
  2356. Error(TXT_MUST_RETURN_VALUE, rnode);
  2357. return;
  2358. }
  2359. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2360. {
  2361. Error(TXT_CANT_RETURN_VALUE, rnode);
  2362. return;
  2363. }
  2364. // Compile the expression
  2365. if( rnode->firstChild )
  2366. {
  2367. // Compile the expression
  2368. asSExprContext expr(engine);
  2369. int r = CompileAssignment(rnode->firstChild, &expr);
  2370. if( r < 0 ) return;
  2371. if( v->type.IsReference() )
  2372. {
  2373. // The expression that gives the reference must not use any of the
  2374. // variables that must be destroyed upon exit, because then it means
  2375. // reference will stay alive while the clean-up is done, which could
  2376. // potentially mean that the reference is invalidated by the clean-up.
  2377. //
  2378. // When the function is returning a reference, the clean-up of the
  2379. // variables must be done before the evaluation of the expression.
  2380. //
  2381. // A reference to a global variable, or a class member for class methods
  2382. // should be allowed to be returned.
  2383. if( !(expr.type.dataType.IsReference() ||
  2384. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2385. {
  2386. // Clean up the potential deferred parameters
  2387. ProcessDeferredParams(&expr);
  2388. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2389. return;
  2390. }
  2391. // No references to local variables, temporary variables, or parameters
  2392. // are allowed to be returned, since they go out of scope when the function
  2393. // returns. Even reference parameters are disallowed, since it is not possible
  2394. // to know the scope of them. The exception is the 'this' pointer, which
  2395. // is treated by the compiler as a local variable, but isn't really so.
  2396. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2397. {
  2398. // Clean up the potential deferred parameters
  2399. ProcessDeferredParams(&expr);
  2400. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2401. return;
  2402. }
  2403. // The type must match exactly as we cannot convert
  2404. // the reference without loosing the original value
  2405. if( !(v->type == expr.type.dataType ||
  2406. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRef(expr.type.dataType))) )
  2407. {
  2408. // Clean up the potential deferred parameters
  2409. ProcessDeferredParams(&expr);
  2410. asCString str;
  2411. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2412. Error(str.AddressOf(), rnode);
  2413. return;
  2414. }
  2415. // The expression must not have any deferred expressions, because the evaluation
  2416. // of these cannot be done without keeping the reference which is not safe
  2417. if( expr.deferredParams.GetLength() )
  2418. {
  2419. // Clean up the potential deferred parameters
  2420. ProcessDeferredParams(&expr);
  2421. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2422. return;
  2423. }
  2424. // Make sure the expression isn't using any local variables that
  2425. // will need to be cleaned up before the function completes
  2426. asCArray<int> usedVars;
  2427. expr.bc.GetVarsUsed(usedVars);
  2428. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  2429. {
  2430. int var = GetVariableSlot(usedVars[n]);
  2431. if( var != -1 )
  2432. {
  2433. asCDataType dt = variableAllocations[var];
  2434. if( dt.IsObject() )
  2435. {
  2436. ProcessDeferredParams(&expr);
  2437. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  2438. return;
  2439. }
  2440. }
  2441. }
  2442. // All objects in the function must be cleaned up before the expression
  2443. // is evaluated, otherwise there is a possibility that the cleanup will
  2444. // invalidate the reference.
  2445. // Destroy the local variables before loading
  2446. // the reference into the register. This will
  2447. // be done before the expression is evaluated.
  2448. DestroyVariables(bc);
  2449. // For primitives the reference is already in the register,
  2450. // but for non-primitives the reference is on the stack so we
  2451. // need to load it into the register
  2452. if( !expr.type.dataType.IsPrimitive() )
  2453. {
  2454. if( !expr.type.dataType.IsObjectHandle() && expr.type.dataType.IsReference() )
  2455. expr.bc.Instr(asBC_RDSPTR);
  2456. expr.bc.Instr(asBC_PopRPtr);
  2457. }
  2458. // There are no temporaries to release so we're done
  2459. }
  2460. else // if( !v->type.IsReference() )
  2461. {
  2462. ProcessPropertyGetAccessor(&expr, rnode);
  2463. // Prepare the value for assignment
  2464. IsVariableInitialized(&expr.type, rnode->firstChild);
  2465. if( v->type.IsPrimitive() )
  2466. {
  2467. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2468. // Implicitly convert the value to the return type
  2469. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2470. // Verify that the conversion was successful
  2471. if( expr.type.dataType != v->type )
  2472. {
  2473. asCString str;
  2474. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2475. Error(str.AddressOf(), rnode);
  2476. r = -1;
  2477. }
  2478. else
  2479. {
  2480. ConvertToVariable(&expr);
  2481. // Clean up the local variables and process deferred parameters
  2482. DestroyVariables(&expr.bc);
  2483. ProcessDeferredParams(&expr);
  2484. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2485. // Load the variable in the register
  2486. if( v->type.GetSizeOnStackDWords() == 1 )
  2487. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2488. else
  2489. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  2490. }
  2491. }
  2492. else if( v->type.IsObject() )
  2493. {
  2494. // Value types are still returned on the heap, so we must
  2495. // copy the value to an object allocated on the heap here
  2496. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0, 0, true);
  2497. // Pop the reference to the temporary variable again
  2498. expr.bc.Pop(AS_PTR_SIZE);
  2499. // Clean up the local variables and process deferred parameters
  2500. DestroyVariables(&expr.bc);
  2501. ProcessDeferredParams(&expr);
  2502. // Load the object pointer into the object register
  2503. // LOADOBJ also clears the address in the variable
  2504. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  2505. // LOADOBJ cleared the address in the variable so the object will not be freed
  2506. // here, but the temporary variable must still be freed so the slot can be reused
  2507. // By releasing without the bytecode we do just that.
  2508. ReleaseTemporaryVariable(expr.type, 0);
  2509. }
  2510. }
  2511. bc->AddCode(&expr.bc);
  2512. }
  2513. else
  2514. {
  2515. // For functions that don't return anything
  2516. // we just detroy the local variables
  2517. DestroyVariables(bc);
  2518. }
  2519. // Jump to the end of the function
  2520. bc->InstrINT(asBC_JMP, 0);
  2521. }
  2522. void asCCompiler::DestroyVariables(asCByteCode *bc)
  2523. {
  2524. // Call destructor on all variables except for the function parameters
  2525. // Put the clean-up in a block to allow exception handler to understand this
  2526. bc->Block(true);
  2527. asCVariableScope *vs = variables;
  2528. while( vs )
  2529. {
  2530. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2531. if( vs->variables[n]->stackOffset > 0 )
  2532. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2533. vs = vs->parent;
  2534. }
  2535. bc->Block(false);
  2536. }
  2537. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  2538. {
  2539. variables = asNEW(asCVariableScope)(variables);
  2540. variables->isBreakScope = isBreakScope;
  2541. variables->isContinueScope = isContinueScope;
  2542. }
  2543. void asCCompiler::RemoveVariableScope()
  2544. {
  2545. if( variables )
  2546. {
  2547. asCVariableScope *var = variables;
  2548. variables = variables->parent;
  2549. asDELETE(var,asCVariableScope);
  2550. }
  2551. }
  2552. void asCCompiler::Error(const char *msg, asCScriptNode *node)
  2553. {
  2554. asCString str;
  2555. int r = 0, c = 0;
  2556. asASSERT( node );
  2557. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2558. builder->WriteError(script->name.AddressOf(), msg, r, c);
  2559. hasCompileErrors = true;
  2560. }
  2561. void asCCompiler::Warning(const char *msg, asCScriptNode *node)
  2562. {
  2563. asCString str;
  2564. int r = 0, c = 0;
  2565. asASSERT( node );
  2566. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2567. builder->WriteWarning(script->name.AddressOf(), msg, r, c);
  2568. }
  2569. void asCCompiler::Information(const char *msg, asCScriptNode *node)
  2570. {
  2571. asCString str;
  2572. int r = 0, c = 0;
  2573. asASSERT( node );
  2574. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2575. builder->WriteInfo(script->name.AddressOf(), msg, r, c, false);
  2576. }
  2577. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  2578. {
  2579. int r = 0, c = 0;
  2580. asASSERT( node );
  2581. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2582. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  2583. {
  2584. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  2585. builder->WriteInfo(script->name.AddressOf(), func->GetDeclaration(true), r, c, false);
  2586. }
  2587. }
  2588. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  2589. {
  2590. return AllocateVariableNotIn(type, isTemporary, 0, forceOnHeap);
  2591. }
  2592. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, asCArray<int> *vars, bool forceOnHeap)
  2593. {
  2594. asCDataType t(type);
  2595. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  2596. t.SetTokenType(ttInt);
  2597. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  2598. t.SetTokenType(ttDouble);
  2599. // Only null handles have the token type unrecognized token
  2600. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  2601. bool isOnHeap = true;
  2602. // TODO: Remove this once the bugs with value types on stack is fixed
  2603. // forceOnHeap = true;
  2604. if( t.IsPrimitive() ||
  2605. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  2606. {
  2607. // Primitives and value types (unless overridden) are allocated on the stack
  2608. isOnHeap = false;
  2609. }
  2610. // Find a free location with the same type
  2611. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  2612. {
  2613. int slot = freeVariables[n];
  2614. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  2615. variableIsTemporary[slot] == isTemporary &&
  2616. variableIsOnHeap[slot] == isOnHeap )
  2617. {
  2618. // We can't return by slot, must count variable sizes
  2619. int offset = GetVariableOffset(slot);
  2620. // Verify that it is not in the list of used variables
  2621. bool isUsed = false;
  2622. if( vars )
  2623. {
  2624. for( asUINT m = 0; m < vars->GetLength(); m++ )
  2625. {
  2626. if( offset == (*vars)[m] )
  2627. {
  2628. isUsed = true;
  2629. break;
  2630. }
  2631. }
  2632. }
  2633. if( !isUsed )
  2634. {
  2635. if( n != freeVariables.GetLength() - 1 )
  2636. freeVariables[n] = freeVariables.PopLast();
  2637. else
  2638. freeVariables.PopLast();
  2639. if( isTemporary )
  2640. tempVariables.PushLast(offset);
  2641. return offset;
  2642. }
  2643. }
  2644. }
  2645. variableAllocations.PushLast(t);
  2646. variableIsTemporary.PushLast(isTemporary);
  2647. variableIsOnHeap.PushLast(isOnHeap);
  2648. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  2649. if( isTemporary )
  2650. tempVariables.PushLast(offset);
  2651. return offset;
  2652. }
  2653. int asCCompiler::GetVariableOffset(int varIndex)
  2654. {
  2655. // Return offset to the last dword on the stack
  2656. int varOffset = 1;
  2657. for( int n = 0; n < varIndex; n++ )
  2658. {
  2659. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2660. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  2661. else
  2662. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  2663. }
  2664. if( varIndex < (int)variableAllocations.GetLength() )
  2665. {
  2666. int size;
  2667. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  2668. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  2669. else
  2670. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  2671. if( size > 1 )
  2672. varOffset += size-1;
  2673. }
  2674. return varOffset;
  2675. }
  2676. int asCCompiler::GetVariableSlot(int offset)
  2677. {
  2678. int varOffset = 1;
  2679. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  2680. {
  2681. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2682. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  2683. else
  2684. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  2685. if( varOffset == offset )
  2686. return n;
  2687. varOffset++;
  2688. }
  2689. return -1;
  2690. }
  2691. bool asCCompiler::IsVariableOnHeap(int offset)
  2692. {
  2693. int varSlot = GetVariableSlot(offset);
  2694. if( varSlot < 0 )
  2695. {
  2696. // This happens for function arguments that are considered as on the heap
  2697. return true;
  2698. }
  2699. return variableIsOnHeap[varSlot];
  2700. }
  2701. void asCCompiler::DeallocateVariable(int offset)
  2702. {
  2703. // Remove temporary variable
  2704. int n;
  2705. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  2706. {
  2707. if( offset == tempVariables[n] )
  2708. {
  2709. if( n == (int)tempVariables.GetLength()-1 )
  2710. tempVariables.PopLast();
  2711. else
  2712. tempVariables[n] = tempVariables.PopLast();
  2713. break;
  2714. }
  2715. }
  2716. n = GetVariableSlot(offset);
  2717. if( n != -1 )
  2718. {
  2719. freeVariables.PushLast(n);
  2720. return;
  2721. }
  2722. // We might get here if the variable was implicitly declared
  2723. // because it was use before a formal declaration, in this case
  2724. // the offset is 0x7FFF
  2725. asASSERT(offset == 0x7FFF);
  2726. }
  2727. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  2728. {
  2729. if( t.isTemporary )
  2730. {
  2731. ReleaseTemporaryVariable(t.stackOffset, bc);
  2732. t.isTemporary = false;
  2733. }
  2734. }
  2735. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  2736. {
  2737. if( bc )
  2738. {
  2739. // We need to call the destructor on the true variable type
  2740. int n = GetVariableSlot(offset);
  2741. asCDataType dt = variableAllocations[n];
  2742. bool isOnHeap = variableIsOnHeap[n];
  2743. // Call destructor
  2744. CallDestructor(dt, offset, isOnHeap, bc);
  2745. }
  2746. DeallocateVariable(offset);
  2747. }
  2748. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  2749. {
  2750. if( ctx->type.dataType.IsReference() )
  2751. {
  2752. if( ctx->type.dataType.IsObject() )
  2753. {
  2754. ctx->type.dataType.MakeReference(false);
  2755. if( generateCode )
  2756. {
  2757. ctx->bc.Instr(asBC_CHKREF);
  2758. ctx->bc.Instr(asBC_RDSPTR);
  2759. }
  2760. }
  2761. else
  2762. {
  2763. // This should never happen as primitives are treated differently
  2764. asASSERT(false);
  2765. }
  2766. }
  2767. }
  2768. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  2769. {
  2770. // Temporary variables are assumed to be initialized
  2771. if( type->isTemporary ) return true;
  2772. // Verify that it is a variable
  2773. if( !type->isVariable ) return true;
  2774. // Find the variable
  2775. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  2776. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  2777. if( v == 0 ) return true;
  2778. if( v->isInitialized ) return true;
  2779. // Complex types don't need this test
  2780. if( v->type.IsObject() ) return true;
  2781. // Mark as initialized so that the user will not be bothered again
  2782. v->isInitialized = true;
  2783. // Write warning
  2784. asCString str;
  2785. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  2786. Warning(str.AddressOf(), node);
  2787. return false;
  2788. }
  2789. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  2790. {
  2791. // Check if the variable is initialized (if it indeed is a variable)
  2792. IsVariableInitialized(&ctx->type, node);
  2793. asCDataType to = ctx->type.dataType;
  2794. to.MakeReference(false);
  2795. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  2796. ProcessDeferredParams(ctx);
  2797. }
  2798. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, asSExprContext *lvalueExpr)
  2799. {
  2800. ProcessPropertyGetAccessor(rctx, node);
  2801. // Make sure the rvalue is initialized if it is a variable
  2802. IsVariableInitialized(&rctx->type, node);
  2803. if( lvalue->IsPrimitive() )
  2804. {
  2805. if( rctx->type.dataType.IsPrimitive() )
  2806. {
  2807. if( rctx->type.dataType.IsReference() )
  2808. {
  2809. // Cannot do implicit conversion of references so we first convert the reference to a variable
  2810. ConvertToVariableNotIn(rctx, lvalueExpr);
  2811. }
  2812. }
  2813. // Implicitly convert the value to the right type
  2814. asCArray<int> usedVars;
  2815. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(usedVars);
  2816. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV, true, &usedVars);
  2817. // Check data type
  2818. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  2819. {
  2820. asCString str;
  2821. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  2822. Error(str.AddressOf(), node);
  2823. rctx->type.SetDummy();
  2824. }
  2825. // Make sure the rvalue is a variable
  2826. if( !rctx->type.isVariable )
  2827. ConvertToVariableNotIn(rctx, lvalueExpr);
  2828. }
  2829. else
  2830. {
  2831. asCDataType to = *lvalue;
  2832. to.MakeReference(false);
  2833. // TODO: ImplicitConversion should know to do this by itself
  2834. // First convert to a handle which will to a reference cast
  2835. if( !lvalue->IsObjectHandle() &&
  2836. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  2837. to.MakeHandle(true);
  2838. // Don't allow the implicit conversion to create an object
  2839. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  2840. if( !lvalue->IsObjectHandle() &&
  2841. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  2842. {
  2843. // Then convert to a reference, which will validate the handle
  2844. to.MakeHandle(false);
  2845. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  2846. }
  2847. // Check data type
  2848. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  2849. {
  2850. asCString str;
  2851. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  2852. Error(str.AddressOf(), node);
  2853. }
  2854. else
  2855. {
  2856. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  2857. if( lvalue->IsObject() )
  2858. asASSERT(!rctx->type.dataType.IsReference());
  2859. }
  2860. }
  2861. }
  2862. bool asCCompiler::IsLValue(asCTypeInfo &type)
  2863. {
  2864. if( type.dataType.IsReadOnly() ) return false;
  2865. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  2866. if( type.isTemporary ) return false;
  2867. return true;
  2868. }
  2869. void asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  2870. {
  2871. if( lvalue->dataType.IsReadOnly() )
  2872. Error(TXT_REF_IS_READ_ONLY, node);
  2873. if( lvalue->dataType.IsPrimitive() )
  2874. {
  2875. if( lvalue->isVariable )
  2876. {
  2877. // Copy the value between the variables directly
  2878. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  2879. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  2880. else
  2881. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  2882. // Mark variable as initialized
  2883. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  2884. if( v ) v->isInitialized = true;
  2885. }
  2886. else if( lvalue->dataType.IsReference() )
  2887. {
  2888. // Copy the value of the variable to the reference in the register
  2889. int s = lvalue->dataType.GetSizeInMemoryBytes();
  2890. if( s == 1 )
  2891. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  2892. else if( s == 2 )
  2893. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  2894. else if( s == 4 )
  2895. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  2896. else if( s == 8 )
  2897. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  2898. }
  2899. else
  2900. {
  2901. Error(TXT_NOT_VALID_LVALUE, node);
  2902. return;
  2903. }
  2904. }
  2905. else if( !lvalue->isExplicitHandle )
  2906. {
  2907. asSExprContext ctx(engine);
  2908. ctx.type = *lvalue;
  2909. Dereference(&ctx, true);
  2910. *lvalue = ctx.type;
  2911. bc->AddCode(&ctx.bc);
  2912. // TODO: Can't this leave deferred output params unhandled?
  2913. // TODO: Should find the opAssign method that implements the default copy behaviour.
  2914. // The beh->copy member will be removed.
  2915. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  2916. if( beh->copy )
  2917. {
  2918. // Call the copy operator
  2919. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  2920. bc->Instr(asBC_PshRPtr);
  2921. }
  2922. else
  2923. {
  2924. // Default copy operator
  2925. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  2926. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  2927. {
  2928. Error(TXT_NO_DEFAULT_COPY_OP, node);
  2929. }
  2930. // Copy larger data types from a reference
  2931. bc->InstrSHORT_DW(asBC_COPY, lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  2932. }
  2933. }
  2934. else
  2935. {
  2936. // TODO: The object handle can be stored in a variable as well
  2937. if( !lvalue->dataType.IsReference() )
  2938. {
  2939. Error(TXT_NOT_VALID_REFERENCE, node);
  2940. return;
  2941. }
  2942. // TODO: optimize: Convert to register based
  2943. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  2944. // Mark variable as initialized
  2945. if( variables )
  2946. {
  2947. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  2948. if( v ) v->isInitialized = true;
  2949. }
  2950. }
  2951. }
  2952. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  2953. {
  2954. bool conversionDone = false;
  2955. asCArray<int> ops;
  2956. asUINT n;
  2957. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  2958. {
  2959. // We need it to be a reference
  2960. if( !ctx->type.dataType.IsReference() )
  2961. {
  2962. asCDataType to = ctx->type.dataType;
  2963. to.MakeReference(true);
  2964. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  2965. }
  2966. if( isExplicit )
  2967. {
  2968. // Allow dynamic cast between object handles (only for script objects).
  2969. // At run time this may result in a null handle,
  2970. // which when used will throw an exception
  2971. conversionDone = true;
  2972. if( generateCode )
  2973. {
  2974. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  2975. // Allocate a temporary variable for the returned object
  2976. int returnOffset = AllocateVariable(to, true);
  2977. // Move the pointer from the object register to the temporary variable
  2978. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  2979. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  2980. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2981. ctx->type.SetVariable(to, returnOffset, true);
  2982. ctx->type.dataType.MakeReference(true);
  2983. }
  2984. else
  2985. {
  2986. ctx->type.dataType = to;
  2987. ctx->type.dataType.MakeReference(true);
  2988. }
  2989. }
  2990. else
  2991. {
  2992. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  2993. {
  2994. conversionDone = true;
  2995. ctx->type.dataType.SetObjectType(to.GetObjectType());
  2996. }
  2997. }
  2998. }
  2999. else
  3000. {
  3001. // Find a suitable registered behaviour
  3002. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3003. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3004. {
  3005. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3006. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3007. {
  3008. int funcId = beh->operators[n+1];
  3009. // Is the operator for the output type?
  3010. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3011. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3012. continue;
  3013. ops.PushLast(funcId);
  3014. }
  3015. }
  3016. // Should only have one behaviour for each output type
  3017. if( ops.GetLength() == 1 )
  3018. {
  3019. if( generateCode )
  3020. {
  3021. // TODO: optimize: Instead of producing bytecode for checking if the handle is
  3022. // null, we can create a special CALLSYS instruction that checks
  3023. // if the object pointer is null and if so sets the object register
  3024. // to null directly without executing the function.
  3025. //
  3026. // Alternatively I could force the ref cast behaviours be global
  3027. // functions with 1 parameter, even though they should still be
  3028. // registered with RegisterObjectBehaviour()
  3029. // Add code to avoid calling the cast behaviour if the handle is already null,
  3030. // because that will raise a null pointer exception due to the cast behaviour
  3031. // being a class method, and the this pointer cannot be null.
  3032. if( ctx->type.isVariable )
  3033. ctx->bc.Pop(AS_PTR_SIZE);
  3034. else
  3035. {
  3036. Dereference(ctx, true);
  3037. ConvertToVariable(ctx);
  3038. }
  3039. #ifdef AS_64BIT_PTR
  3040. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt64, false), true);
  3041. ctx->bc.InstrW_QW(asBC_SetV8, offset, 0);
  3042. ctx->bc.InstrW_W(asBC_CMPi64, ctx->type.stackOffset, offset);
  3043. DeallocateVariable(offset);
  3044. #else
  3045. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt, false), true);
  3046. ctx->bc.InstrW_DW(asBC_SetV4, offset, 0);
  3047. ctx->bc.InstrW_W(asBC_CMPi, ctx->type.stackOffset, offset);
  3048. DeallocateVariable(offset);
  3049. #endif
  3050. int afterLabel = nextLabel++;
  3051. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3052. // Call the cast operator
  3053. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3054. ctx->bc.Instr(asBC_RDSPTR);
  3055. ctx->type.dataType.MakeReference(false);
  3056. asCTypeInfo objType = ctx->type;
  3057. asCArray<asSExprContext *> args;
  3058. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3059. ctx->bc.Pop(AS_PTR_SIZE);
  3060. int endLabel = nextLabel++;
  3061. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3062. ctx->bc.Label((short)afterLabel);
  3063. // Make a NULL pointer
  3064. #ifdef AS_64BIT_PTR
  3065. ctx->bc.InstrW_QW(asBC_SetV8, ctx->type.stackOffset, 0);
  3066. #else
  3067. ctx->bc.InstrW_DW(asBC_SetV4, ctx->type.stackOffset, 0);
  3068. #endif
  3069. ctx->bc.Label((short)endLabel);
  3070. // Since we're receiving a handle, we can release the original variable
  3071. ReleaseTemporaryVariable(objType, &ctx->bc);
  3072. // Push the reference to the handle on the stack
  3073. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3074. }
  3075. else
  3076. {
  3077. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3078. ctx->type.Set(func->returnType);
  3079. }
  3080. }
  3081. else if( ops.GetLength() > 1 )
  3082. {
  3083. // It shouldn't be possible to have more than one, should it?
  3084. asASSERT( false );
  3085. }
  3086. }
  3087. return conversionDone;
  3088. }
  3089. void asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3090. {
  3091. asCDataType to = toOrig;
  3092. to.MakeReference(false);
  3093. asASSERT( !ctx->type.dataType.IsReference() );
  3094. // Start by implicitly converting constant values
  3095. if( ctx->type.isConstant )
  3096. ImplicitConversionConstant(ctx, to, node, convType);
  3097. // A primitive is const or not
  3098. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3099. if( to == ctx->type.dataType )
  3100. return;
  3101. // Allow implicit conversion between numbers
  3102. if( generateCode )
  3103. {
  3104. // Convert smaller types to 32bit first
  3105. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3106. if( s < 4 )
  3107. {
  3108. ConvertToTempVariableNotIn(ctx, reservedVars);
  3109. if( ctx->type.dataType.IsIntegerType() )
  3110. {
  3111. if( s == 1 )
  3112. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3113. else if( s == 2 )
  3114. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3115. ctx->type.dataType.SetTokenType(ttInt);
  3116. }
  3117. else if( ctx->type.dataType.IsUnsignedType() )
  3118. {
  3119. if( s == 1 )
  3120. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3121. else if( s == 2 )
  3122. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3123. ctx->type.dataType.SetTokenType(ttUInt);
  3124. }
  3125. }
  3126. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3127. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3128. {
  3129. if( ctx->type.dataType.IsIntegerType() ||
  3130. ctx->type.dataType.IsUnsignedType() ||
  3131. ctx->type.dataType.IsEnumType() )
  3132. {
  3133. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3134. {
  3135. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3136. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3137. }
  3138. else
  3139. {
  3140. ConvertToTempVariableNotIn(ctx, reservedVars);
  3141. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3142. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3143. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3144. ctx->type.SetVariable(to, offset, true);
  3145. }
  3146. }
  3147. else if( ctx->type.dataType.IsFloatType() )
  3148. {
  3149. ConvertToTempVariableNotIn(ctx, reservedVars);
  3150. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3151. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3152. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3153. }
  3154. else if( ctx->type.dataType.IsDoubleType() )
  3155. {
  3156. ConvertToTempVariableNotIn(ctx, reservedVars);
  3157. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3158. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3159. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3160. ctx->type.SetVariable(to, offset, true);
  3161. }
  3162. // Convert to smaller integer if necessary
  3163. int s = to.GetSizeInMemoryBytes();
  3164. if( s < 4 )
  3165. {
  3166. ConvertToTempVariableNotIn(ctx, reservedVars);
  3167. if( s == 1 )
  3168. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3169. else if( s == 2 )
  3170. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3171. }
  3172. }
  3173. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3174. {
  3175. if( ctx->type.dataType.IsIntegerType() ||
  3176. ctx->type.dataType.IsUnsignedType() ||
  3177. ctx->type.dataType.IsEnumType() )
  3178. {
  3179. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3180. {
  3181. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3182. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3183. }
  3184. else
  3185. {
  3186. ConvertToTempVariableNotIn(ctx, reservedVars);
  3187. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3188. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3189. if( ctx->type.dataType.IsUnsignedType() )
  3190. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3191. else
  3192. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3193. ctx->type.SetVariable(to, offset, true);
  3194. }
  3195. }
  3196. else if( ctx->type.dataType.IsFloatType() )
  3197. {
  3198. ConvertToTempVariableNotIn(ctx, reservedVars);
  3199. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3200. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3201. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3202. ctx->type.SetVariable(to, offset, true);
  3203. }
  3204. else if( ctx->type.dataType.IsDoubleType() )
  3205. {
  3206. ConvertToTempVariableNotIn(ctx, reservedVars);
  3207. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3208. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3209. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3210. }
  3211. }
  3212. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3213. {
  3214. if( ctx->type.dataType.IsIntegerType() ||
  3215. ctx->type.dataType.IsUnsignedType() ||
  3216. ctx->type.dataType.IsEnumType() )
  3217. {
  3218. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3219. {
  3220. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3221. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3222. }
  3223. else
  3224. {
  3225. ConvertToTempVariableNotIn(ctx, reservedVars);
  3226. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3227. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3228. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3229. ctx->type.SetVariable(to, offset, true);
  3230. }
  3231. }
  3232. else if( ctx->type.dataType.IsFloatType() )
  3233. {
  3234. ConvertToTempVariableNotIn(ctx, reservedVars);
  3235. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3236. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3237. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3238. }
  3239. else if( ctx->type.dataType.IsDoubleType() )
  3240. {
  3241. ConvertToTempVariableNotIn(ctx, reservedVars);
  3242. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3243. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3244. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3245. ctx->type.SetVariable(to, offset, true);
  3246. }
  3247. // Convert to smaller integer if necessary
  3248. int s = to.GetSizeInMemoryBytes();
  3249. if( s < 4 )
  3250. {
  3251. ConvertToTempVariableNotIn(ctx, reservedVars);
  3252. if( s == 1 )
  3253. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3254. else if( s == 2 )
  3255. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3256. }
  3257. }
  3258. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3259. {
  3260. if( ctx->type.dataType.IsIntegerType() ||
  3261. ctx->type.dataType.IsUnsignedType() ||
  3262. ctx->type.dataType.IsEnumType() )
  3263. {
  3264. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3265. {
  3266. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3267. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3268. }
  3269. else
  3270. {
  3271. ConvertToTempVariableNotIn(ctx, reservedVars);
  3272. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3273. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3274. if( ctx->type.dataType.IsUnsignedType() )
  3275. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3276. else
  3277. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3278. ctx->type.SetVariable(to, offset, true);
  3279. }
  3280. }
  3281. else if( ctx->type.dataType.IsFloatType() )
  3282. {
  3283. ConvertToTempVariableNotIn(ctx, reservedVars);
  3284. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3285. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3286. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3287. ctx->type.SetVariable(to, offset, true);
  3288. }
  3289. else if( ctx->type.dataType.IsDoubleType() )
  3290. {
  3291. ConvertToTempVariableNotIn(ctx, reservedVars);
  3292. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3293. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3294. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3295. }
  3296. }
  3297. else if( to.IsFloatType() )
  3298. {
  3299. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3300. {
  3301. ConvertToTempVariableNotIn(ctx, reservedVars);
  3302. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3303. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3304. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3305. }
  3306. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3307. {
  3308. ConvertToTempVariableNotIn(ctx, reservedVars);
  3309. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3310. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3311. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  3312. ctx->type.SetVariable(to, offset, true);
  3313. }
  3314. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3315. {
  3316. ConvertToTempVariableNotIn(ctx, reservedVars);
  3317. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  3318. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3319. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3320. }
  3321. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3322. {
  3323. ConvertToTempVariableNotIn(ctx, reservedVars);
  3324. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3325. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3326. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  3327. ctx->type.SetVariable(to, offset, true);
  3328. }
  3329. else if( ctx->type.dataType.IsDoubleType() )
  3330. {
  3331. ConvertToTempVariableNotIn(ctx, reservedVars);
  3332. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3333. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3334. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  3335. ctx->type.SetVariable(to, offset, true);
  3336. }
  3337. }
  3338. else if( to.IsDoubleType() )
  3339. {
  3340. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3341. {
  3342. ConvertToTempVariableNotIn(ctx, reservedVars);
  3343. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3344. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3345. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  3346. ctx->type.SetVariable(to, offset, true);
  3347. }
  3348. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3349. {
  3350. ConvertToTempVariableNotIn(ctx, reservedVars);
  3351. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  3352. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3353. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3354. }
  3355. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3356. {
  3357. ConvertToTempVariableNotIn(ctx, reservedVars);
  3358. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3359. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3360. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  3361. ctx->type.SetVariable(to, offset, true);
  3362. }
  3363. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3364. {
  3365. ConvertToTempVariableNotIn(ctx, reservedVars);
  3366. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  3367. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3368. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3369. }
  3370. else if( ctx->type.dataType.IsFloatType() )
  3371. {
  3372. ConvertToTempVariableNotIn(ctx, reservedVars);
  3373. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3374. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3375. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  3376. ctx->type.SetVariable(to, offset, true);
  3377. }
  3378. }
  3379. }
  3380. else
  3381. {
  3382. if( (to.IsIntegerType() || to.IsUnsignedType() ||
  3383. to.IsFloatType() || to.IsDoubleType() ||
  3384. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  3385. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  3386. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
  3387. ctx->type.dataType.IsEnumType()) )
  3388. {
  3389. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3390. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3391. }
  3392. }
  3393. // Primitive types on the stack, can be const or non-const
  3394. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3395. }
  3396. void asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3397. {
  3398. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  3399. ctx->type.dataType.IsNullHandle() );
  3400. // No conversion from void to any other type
  3401. if( ctx->type.dataType.GetTokenType() == ttVoid )
  3402. return;
  3403. // Do we want a var type?
  3404. if( to.GetTokenType() == ttQuestion )
  3405. {
  3406. // Any type can be converted to a var type, but only when not generating code
  3407. asASSERT( !generateCode );
  3408. ctx->type.dataType = to;
  3409. return;
  3410. }
  3411. // Do we want a primitive?
  3412. else if( to.IsPrimitive() )
  3413. {
  3414. if( !ctx->type.dataType.IsPrimitive() )
  3415. ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3416. else
  3417. ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3418. }
  3419. else // The target is a complex type
  3420. {
  3421. if( ctx->type.dataType.IsPrimitive() )
  3422. ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3423. else
  3424. ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3425. }
  3426. }
  3427. void asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3428. {
  3429. if( ctx->type.isExplicitHandle )
  3430. {
  3431. // An explicit handle cannot be converted to a primitive
  3432. if( convType != asIC_IMPLICIT_CONV && node )
  3433. {
  3434. asCString str;
  3435. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3436. Error(str.AddressOf(), node);
  3437. }
  3438. return;
  3439. }
  3440. // TODO: Must use the const cast behaviour if the object is read-only
  3441. // Find matching value cast behaviours
  3442. // Here we're only interested in those that convert the type to a primitive type
  3443. asCArray<int> funcs;
  3444. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3445. if( beh )
  3446. {
  3447. if( convType == asIC_EXPLICIT_VAL_CAST )
  3448. {
  3449. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3450. {
  3451. // accept both implicit and explicit cast
  3452. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3453. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3454. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3455. funcs.PushLast(beh->operators[n+1]);
  3456. }
  3457. }
  3458. else
  3459. {
  3460. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3461. {
  3462. // accept only implicit cast
  3463. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3464. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3465. funcs.PushLast(beh->operators[n+1]);
  3466. }
  3467. }
  3468. }
  3469. // This matrix describes the priorities of the types to search for, for each target type
  3470. // The first column is the target type, the priorities goes from left to right
  3471. eTokenType matchMtx[10][10] =
  3472. {
  3473. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3474. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3475. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3476. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3477. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3478. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3479. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  3480. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  3481. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  3482. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  3483. };
  3484. // Which row to use?
  3485. eTokenType *row = 0;
  3486. for( unsigned int type = 0; type < 10; type++ )
  3487. {
  3488. if( to.GetTokenType() == matchMtx[type][0] )
  3489. {
  3490. row = &matchMtx[type][0];
  3491. break;
  3492. }
  3493. }
  3494. // Find the best matching cast operator
  3495. int funcId = 0;
  3496. if( row )
  3497. {
  3498. asCDataType target(to);
  3499. // Priority goes from left to right in the matrix
  3500. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  3501. {
  3502. target.SetTokenType(row[attempt]);
  3503. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3504. {
  3505. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  3506. if( descr->returnType.IsEqualExceptConst(target) )
  3507. {
  3508. funcId = funcs[n];
  3509. break;
  3510. }
  3511. }
  3512. }
  3513. }
  3514. // Did we find a suitable function?
  3515. if( funcId != 0 )
  3516. {
  3517. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  3518. if( generateCode )
  3519. {
  3520. asCTypeInfo objType = ctx->type;
  3521. Dereference(ctx, true);
  3522. PerformFunctionCall(funcId, ctx);
  3523. ReleaseTemporaryVariable(objType, &ctx->bc);
  3524. }
  3525. else
  3526. ctx->type.Set(descr->returnType);
  3527. // Allow one more implicit conversion to another primitive type
  3528. ImplicitConversion(ctx, to, node, convType, generateCode, reservedVars, false);
  3529. }
  3530. else
  3531. {
  3532. if( convType != asIC_IMPLICIT_CONV && node )
  3533. {
  3534. asCString str;
  3535. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3536. Error(str.AddressOf(), node);
  3537. }
  3538. }
  3539. }
  3540. void asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3541. {
  3542. // Convert null to any object type handle, but not to a non-handle type
  3543. if( ctx->type.IsNullConstant() )
  3544. {
  3545. if( to.IsObjectHandle() )
  3546. ctx->type.dataType = to;
  3547. return;
  3548. }
  3549. // First attempt to convert the base type without instanciating another instance
  3550. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3551. {
  3552. // If the to type is an interface and the from type implements it, then we can convert it immediately
  3553. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  3554. {
  3555. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3556. }
  3557. // If the to type is a class and the from type derives from it, then we can convert it immediately
  3558. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3559. {
  3560. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3561. }
  3562. // If the types are not equal yet, then we may still be able to find a reference cast
  3563. if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  3564. {
  3565. // A ref cast must not remove the constness
  3566. bool isConst = false;
  3567. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  3568. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  3569. isConst = true;
  3570. // We may still be able to find an implicit ref cast behaviour
  3571. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  3572. ctx->type.dataType.MakeHandleToConst(isConst);
  3573. }
  3574. }
  3575. // If the base type is still different, and we are allowed to instance
  3576. // another object then we can try an implicit value cast
  3577. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  3578. {
  3579. // TODO: Implement support for implicit constructor/factory
  3580. asCArray<int> funcs;
  3581. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3582. if( beh )
  3583. {
  3584. if( convType == asIC_EXPLICIT_VAL_CAST )
  3585. {
  3586. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3587. {
  3588. // accept both implicit and explicit cast
  3589. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3590. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3591. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3592. funcs.PushLast(beh->operators[n+1]);
  3593. }
  3594. }
  3595. else
  3596. {
  3597. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3598. {
  3599. // accept only implicit cast
  3600. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3601. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3602. funcs.PushLast(beh->operators[n+1]);
  3603. }
  3604. }
  3605. }
  3606. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  3607. asASSERT( funcs.GetLength() <= 1 );
  3608. if( funcs.GetLength() == 1 )
  3609. {
  3610. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  3611. if( generateCode )
  3612. {
  3613. asCTypeInfo objType = ctx->type;
  3614. Dereference(ctx, true);
  3615. PerformFunctionCall(funcs[0], ctx);
  3616. ReleaseTemporaryVariable(objType, &ctx->bc);
  3617. }
  3618. else
  3619. ctx->type.Set(f->returnType);
  3620. }
  3621. }
  3622. // If we still haven't converted the base type to the correct type, then there is no need to continue
  3623. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3624. return;
  3625. // Convert matching function types
  3626. if( to.GetFuncDef() && ctx->type.dataType.GetFuncDef() &&
  3627. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  3628. {
  3629. asCScriptFunction *toFunc = to.GetFuncDef();
  3630. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  3631. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  3632. {
  3633. ctx->type.dataType.SetFuncDef(toFunc);
  3634. }
  3635. }
  3636. if( to.IsObjectHandle() )
  3637. {
  3638. // reference to handle -> handle
  3639. // reference -> handle
  3640. // object -> handle
  3641. // handle -> reference to handle
  3642. // reference -> reference to handle
  3643. // object -> reference to handle
  3644. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  3645. // If the rvalue is a handle to a const object, then
  3646. // the lvalue must also be a handle to a const object
  3647. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  3648. {
  3649. if( convType != asIC_IMPLICIT_CONV )
  3650. {
  3651. asASSERT(node);
  3652. asCString str;
  3653. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3654. Error(str.AddressOf(), node);
  3655. }
  3656. }
  3657. if( !ctx->type.dataType.IsObjectHandle() )
  3658. {
  3659. // An object type can be directly converted to a handle of the same type
  3660. if( ctx->type.dataType.SupportHandles() )
  3661. {
  3662. ctx->type.dataType.MakeHandle(true);
  3663. }
  3664. if( ctx->type.dataType.IsObjectHandle() )
  3665. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3666. if( to.IsHandleToConst() && ctx->type.dataType.IsObjectHandle() )
  3667. ctx->type.dataType.MakeHandleToConst(true);
  3668. }
  3669. else
  3670. {
  3671. // A handle to non-const can be converted to a
  3672. // handle to const, but not the other way
  3673. if( to.IsHandleToConst() )
  3674. ctx->type.dataType.MakeHandleToConst(true);
  3675. // A const handle can be converted to a non-const
  3676. // handle and vice versa as the handle is just a value
  3677. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3678. }
  3679. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  3680. {
  3681. if( generateCode )
  3682. {
  3683. // If the input type is a handle, then a simple ref copy is enough
  3684. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3685. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  3686. // If the input type is read-only we'll need to temporarily
  3687. // remove this constness, otherwise the assignment will fail
  3688. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  3689. ctx->type.dataType.MakeReadOnly(false);
  3690. // If the object already is a temporary variable, then the copy
  3691. // doesn't have to be made as it is already a unique object
  3692. PrepareTemporaryObject(node, ctx, reservedVars);
  3693. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  3694. ctx->type.isExplicitHandle = isExplicitHandle;
  3695. }
  3696. // A non-reference can be converted to a reference,
  3697. // by putting the value in a temporary variable
  3698. ctx->type.dataType.MakeReference(true);
  3699. // Since it is a new temporary variable it doesn't have to be const
  3700. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3701. }
  3702. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  3703. {
  3704. Dereference(ctx, generateCode);
  3705. }
  3706. }
  3707. else
  3708. {
  3709. if( !to.IsReference() )
  3710. {
  3711. // reference to handle -> object
  3712. // handle -> object
  3713. // reference -> object
  3714. // An implicit handle can be converted to an object by adding a check for null pointer
  3715. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  3716. {
  3717. if( generateCode )
  3718. ctx->bc.Instr(asBC_CHKREF);
  3719. ctx->type.dataType.MakeHandle(false);
  3720. }
  3721. // A const object can be converted to a non-const object through a copy
  3722. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  3723. allowObjectConstruct )
  3724. {
  3725. // Does the object type allow a copy to be made?
  3726. if( ctx->type.dataType.CanBeCopied() )
  3727. {
  3728. if( generateCode )
  3729. {
  3730. // Make a temporary object with the copy
  3731. PrepareTemporaryObject(node, ctx, reservedVars);
  3732. }
  3733. // In case the object was already in a temporary variable, then the function
  3734. // didn't really do anything so we need to remove the constness here
  3735. ctx->type.dataType.MakeReadOnly(false);
  3736. }
  3737. }
  3738. if( ctx->type.dataType.IsReference() )
  3739. {
  3740. Dereference(ctx, generateCode);
  3741. // TODO: Can't this leave unhandled deferred output params?
  3742. }
  3743. // A non-const object can be converted to a const object directly
  3744. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  3745. {
  3746. ctx->type.dataType.MakeReadOnly(true);
  3747. }
  3748. }
  3749. else
  3750. {
  3751. // reference to handle -> reference
  3752. // handle -> reference
  3753. // object -> reference
  3754. if( ctx->type.dataType.IsReference() )
  3755. {
  3756. // A reference to a handle can be converted to a reference to an object
  3757. // by first reading the address, then verifying that it is not null, then putting the address back on the stack
  3758. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  3759. {
  3760. ctx->type.dataType.MakeHandle(false);
  3761. if( generateCode )
  3762. ctx->bc.Instr(asBC_ChkRefS);
  3763. }
  3764. // A reference to a non-const can be converted to a reference to a const
  3765. if( to.IsReadOnly() )
  3766. ctx->type.dataType.MakeReadOnly(true);
  3767. else if( ctx->type.dataType.IsReadOnly() )
  3768. {
  3769. // A reference to a const can be converted to a reference to a
  3770. // non-const by copying the object to a temporary variable
  3771. ctx->type.dataType.MakeReadOnly(false);
  3772. if( generateCode )
  3773. {
  3774. // If the object already is a temporary variable, then the copy
  3775. // doesn't have to be made as it is already a unique object
  3776. PrepareTemporaryObject(node, ctx, reservedVars);
  3777. }
  3778. }
  3779. }
  3780. else
  3781. {
  3782. // A value type allocated on the stack is differentiated
  3783. // by it not being a reference. But it can be handled as
  3784. // reference by pushing the pointer on the stack
  3785. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  3786. (ctx->type.isVariable || ctx->type.isTemporary) &&
  3787. !IsVariableOnHeap(ctx->type.stackOffset) )
  3788. {
  3789. // Actually the pointer is already pushed on the stack in
  3790. // CompileVariableAccess, so we don't need to do anything else
  3791. }
  3792. else if( generateCode )
  3793. {
  3794. // A non-reference can be converted to a reference,
  3795. // by putting the value in a temporary variable
  3796. // If the input type is read-only we'll need to temporarily
  3797. // remove this constness, otherwise the assignment will fail
  3798. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  3799. ctx->type.dataType.MakeReadOnly(false);
  3800. // If the object already is a temporary variable, then the copy
  3801. // doesn't have to be made as it is already a unique object
  3802. PrepareTemporaryObject(node, ctx, reservedVars);
  3803. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  3804. }
  3805. // A handle can be converted to a reference, by checking for a null pointer
  3806. if( ctx->type.dataType.IsObjectHandle() )
  3807. {
  3808. if( generateCode )
  3809. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  3810. ctx->type.dataType.MakeHandle(false);
  3811. ctx->type.dataType.MakeReference(true);
  3812. // TODO: Make sure a handle to const isn't converted to non-const reference
  3813. }
  3814. else
  3815. {
  3816. // This may look strange as the conversion was to make the expression a reference
  3817. // but a value type allocated on the stack is a reference even without the type
  3818. // being marked as such.
  3819. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  3820. }
  3821. // TODO: If the variable is an object allocated on the stack, this is not true
  3822. // Since it is a new temporary variable it doesn't have to be const
  3823. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3824. }
  3825. }
  3826. }
  3827. }
  3828. void asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, asCArray<int> * /*reservedVars*/, bool /*allowObjectConstruct*/)
  3829. {
  3830. // TODO: This function should call the constructor/factory that has been marked as available
  3831. // for implicit conversions. The code will likely be similar to CallCopyConstructor()
  3832. }
  3833. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  3834. {
  3835. asASSERT(from->type.isConstant);
  3836. // TODO: node should be the node of the value that is
  3837. // converted (not the operator that provokes the implicit
  3838. // conversion)
  3839. // If the base type is correct there is no more to do
  3840. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  3841. // References cannot be constants
  3842. if( from->type.dataType.IsReference() ) return;
  3843. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3844. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3845. {
  3846. if( from->type.dataType.IsFloatType() ||
  3847. from->type.dataType.IsDoubleType() ||
  3848. from->type.dataType.IsUnsignedType() ||
  3849. from->type.dataType.IsIntegerType() ||
  3850. from->type.dataType.IsEnumType() )
  3851. {
  3852. // Transform the value
  3853. // Float constants can be implicitly converted to int
  3854. if( from->type.dataType.IsFloatType() )
  3855. {
  3856. float fc = from->type.floatValue;
  3857. int ic = int(fc);
  3858. if( float(ic) != fc )
  3859. {
  3860. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3861. }
  3862. from->type.intValue = ic;
  3863. }
  3864. // Double constants can be implicitly converted to int
  3865. else if( from->type.dataType.IsDoubleType() )
  3866. {
  3867. double fc = from->type.doubleValue;
  3868. int ic = int(fc);
  3869. if( double(ic) != fc )
  3870. {
  3871. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3872. }
  3873. from->type.intValue = ic;
  3874. }
  3875. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  3876. {
  3877. // Verify that it is possible to convert to signed without getting negative
  3878. if( from->type.intValue < 0 )
  3879. {
  3880. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  3881. }
  3882. // Convert to 32bit
  3883. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3884. from->type.intValue = from->type.byteValue;
  3885. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3886. from->type.intValue = from->type.wordValue;
  3887. }
  3888. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  3889. {
  3890. // Convert to 32bit
  3891. from->type.intValue = int(from->type.qwordValue);
  3892. }
  3893. else if( from->type.dataType.IsIntegerType() &&
  3894. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  3895. {
  3896. // Convert to 32bit
  3897. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3898. from->type.intValue = (signed char)from->type.byteValue;
  3899. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3900. from->type.intValue = (short)from->type.wordValue;
  3901. }
  3902. else if( from->type.dataType.IsEnumType() )
  3903. {
  3904. // Enum type is already an integer type
  3905. }
  3906. // Set the resulting type
  3907. if( to.IsEnumType() )
  3908. from->type.dataType = to;
  3909. else
  3910. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  3911. }
  3912. // Check if a downsize is necessary
  3913. if( to.IsIntegerType() &&
  3914. from->type.dataType.IsIntegerType() &&
  3915. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  3916. {
  3917. // Verify if it is possible
  3918. if( to.GetSizeInMemoryBytes() == 1 )
  3919. {
  3920. if( char(from->type.intValue) != from->type.intValue )
  3921. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  3922. from->type.byteValue = char(from->type.intValue);
  3923. }
  3924. else if( to.GetSizeInMemoryBytes() == 2 )
  3925. {
  3926. if( short(from->type.intValue) != from->type.intValue )
  3927. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  3928. from->type.wordValue = short(from->type.intValue);
  3929. }
  3930. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  3931. }
  3932. }
  3933. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3934. {
  3935. // Float constants can be implicitly converted to int
  3936. if( from->type.dataType.IsFloatType() )
  3937. {
  3938. float fc = from->type.floatValue;
  3939. asINT64 ic = asINT64(fc);
  3940. if( float(ic) != fc )
  3941. {
  3942. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3943. }
  3944. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  3945. from->type.qwordValue = ic;
  3946. }
  3947. // Double constants can be implicitly converted to int
  3948. else if( from->type.dataType.IsDoubleType() )
  3949. {
  3950. double fc = from->type.doubleValue;
  3951. asINT64 ic = asINT64(fc);
  3952. if( double(ic) != fc )
  3953. {
  3954. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3955. }
  3956. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  3957. from->type.qwordValue = ic;
  3958. }
  3959. else if( from->type.dataType.IsUnsignedType() )
  3960. {
  3961. // Convert to 64bit
  3962. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3963. from->type.qwordValue = from->type.byteValue;
  3964. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3965. from->type.qwordValue = from->type.wordValue;
  3966. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  3967. from->type.qwordValue = from->type.dwordValue;
  3968. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  3969. {
  3970. if( asINT64(from->type.qwordValue) < 0 )
  3971. {
  3972. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  3973. }
  3974. }
  3975. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  3976. }
  3977. else if( from->type.dataType.IsEnumType() )
  3978. {
  3979. from->type.qwordValue = from->type.intValue;
  3980. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  3981. }
  3982. else if( from->type.dataType.IsIntegerType() )
  3983. {
  3984. // Convert to 64bit
  3985. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3986. from->type.qwordValue = (signed char)from->type.byteValue;
  3987. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3988. from->type.qwordValue = (short)from->type.wordValue;
  3989. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  3990. from->type.qwordValue = from->type.intValue;
  3991. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  3992. }
  3993. }
  3994. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3995. {
  3996. if( from->type.dataType.IsFloatType() )
  3997. {
  3998. float fc = from->type.floatValue;
  3999. int uic = int(fc);
  4000. if( float(uic) != fc )
  4001. {
  4002. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4003. }
  4004. else if( uic < 0 )
  4005. {
  4006. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4007. }
  4008. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4009. from->type.intValue = uic;
  4010. // Try once more, in case of a smaller type
  4011. ImplicitConversionConstant(from, to, node, convType);
  4012. }
  4013. else if( from->type.dataType.IsDoubleType() )
  4014. {
  4015. double fc = from->type.doubleValue;
  4016. int uic = int(fc);
  4017. if( double(uic) != fc )
  4018. {
  4019. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4020. }
  4021. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4022. from->type.intValue = uic;
  4023. // Try once more, in case of a smaller type
  4024. ImplicitConversionConstant(from, to, node, convType);
  4025. }
  4026. else if( from->type.dataType.IsEnumType() )
  4027. {
  4028. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4029. // Try once more, in case of a smaller type
  4030. ImplicitConversionConstant(from, to, node, convType);
  4031. }
  4032. else if( from->type.dataType.IsIntegerType() )
  4033. {
  4034. // Verify that it is possible to convert to unsigned without loosing negative
  4035. if( from->type.intValue < 0 )
  4036. {
  4037. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4038. }
  4039. // Convert to 32bit
  4040. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4041. from->type.intValue = (signed char)from->type.byteValue;
  4042. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4043. from->type.intValue = (short)from->type.wordValue;
  4044. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4045. // Try once more, in case of a smaller type
  4046. ImplicitConversionConstant(from, to, node, convType);
  4047. }
  4048. else if( from->type.dataType.IsUnsignedType() &&
  4049. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4050. {
  4051. // Convert to 32bit
  4052. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4053. from->type.dwordValue = from->type.byteValue;
  4054. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4055. from->type.dwordValue = from->type.wordValue;
  4056. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4057. // Try once more, in case of a smaller type
  4058. ImplicitConversionConstant(from, to, node, convType);
  4059. }
  4060. else if( from->type.dataType.IsUnsignedType() &&
  4061. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4062. {
  4063. // Verify if it is possible
  4064. if( to.GetSizeInMemoryBytes() == 1 )
  4065. {
  4066. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  4067. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4068. from->type.byteValue = asBYTE(from->type.dwordValue);
  4069. }
  4070. else if( to.GetSizeInMemoryBytes() == 2 )
  4071. {
  4072. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  4073. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4074. from->type.wordValue = asWORD(from->type.dwordValue);
  4075. }
  4076. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4077. }
  4078. }
  4079. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4080. {
  4081. if( from->type.dataType.IsFloatType() )
  4082. {
  4083. float fc = from->type.floatValue;
  4084. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4085. asQWORD uic = asQWORD(asINT64(fc));
  4086. // TODO: MSVC6 doesn't permit UINT64 to double
  4087. if( float((signed)uic) != fc )
  4088. {
  4089. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4090. }
  4091. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4092. from->type.qwordValue = uic;
  4093. }
  4094. else if( from->type.dataType.IsDoubleType() )
  4095. {
  4096. double fc = from->type.doubleValue;
  4097. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4098. asQWORD uic = asQWORD(asINT64(fc));
  4099. // TODO: MSVC6 doesn't permit UINT64 to double
  4100. if( double((signed)uic) != fc )
  4101. {
  4102. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4103. }
  4104. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4105. from->type.qwordValue = uic;
  4106. }
  4107. else if( from->type.dataType.IsEnumType() )
  4108. {
  4109. from->type.qwordValue = (asINT64)from->type.intValue;
  4110. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4111. }
  4112. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4113. {
  4114. // Convert to 64bit
  4115. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4116. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  4117. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4118. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  4119. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4120. from->type.qwordValue = (asINT64)from->type.intValue;
  4121. // Verify that it is possible to convert to unsigned without loosing negative
  4122. if( asINT64(from->type.qwordValue) < 0 )
  4123. {
  4124. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4125. }
  4126. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4127. }
  4128. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4129. {
  4130. // Verify that it is possible to convert to unsigned without loosing negative
  4131. if( asINT64(from->type.qwordValue) < 0 )
  4132. {
  4133. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4134. }
  4135. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4136. }
  4137. else if( from->type.dataType.IsUnsignedType() )
  4138. {
  4139. // Convert to 64bit
  4140. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4141. from->type.qwordValue = from->type.byteValue;
  4142. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4143. from->type.qwordValue = from->type.wordValue;
  4144. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4145. from->type.qwordValue = from->type.dwordValue;
  4146. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4147. }
  4148. }
  4149. else if( to.IsFloatType() )
  4150. {
  4151. if( from->type.dataType.IsDoubleType() )
  4152. {
  4153. double ic = from->type.doubleValue;
  4154. float fc = float(ic);
  4155. if( double(fc) != ic )
  4156. {
  4157. asCString str;
  4158. str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  4159. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str.AddressOf(), node);
  4160. }
  4161. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4162. from->type.floatValue = fc;
  4163. }
  4164. else if( from->type.dataType.IsEnumType() )
  4165. {
  4166. float fc = float(from->type.intValue);
  4167. if( int(fc) != from->type.intValue )
  4168. {
  4169. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4170. }
  4171. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4172. from->type.floatValue = fc;
  4173. }
  4174. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4175. {
  4176. // Must properly convert value in case the from value is smaller
  4177. int ic;
  4178. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4179. ic = (signed char)from->type.byteValue;
  4180. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4181. ic = (short)from->type.wordValue;
  4182. else
  4183. ic = from->type.intValue;
  4184. float fc = float(ic);
  4185. if( int(fc) != ic )
  4186. {
  4187. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4188. }
  4189. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4190. from->type.floatValue = fc;
  4191. }
  4192. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4193. {
  4194. float fc = float(asINT64(from->type.qwordValue));
  4195. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4196. {
  4197. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4198. }
  4199. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4200. from->type.floatValue = fc;
  4201. }
  4202. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4203. {
  4204. // Must properly convert value in case the from value is smaller
  4205. unsigned int uic;
  4206. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4207. uic = from->type.byteValue;
  4208. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4209. uic = from->type.wordValue;
  4210. else
  4211. uic = from->type.dwordValue;
  4212. float fc = float(uic);
  4213. if( (unsigned int)(fc) != uic )
  4214. {
  4215. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4216. }
  4217. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4218. from->type.floatValue = fc;
  4219. }
  4220. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4221. {
  4222. // TODO: MSVC6 doesn't permit UINT64 to double
  4223. float fc = float((signed)from->type.qwordValue);
  4224. if( asQWORD(fc) != from->type.qwordValue )
  4225. {
  4226. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4227. }
  4228. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4229. from->type.floatValue = fc;
  4230. }
  4231. }
  4232. else if( to.IsDoubleType() )
  4233. {
  4234. if( from->type.dataType.IsFloatType() )
  4235. {
  4236. float ic = from->type.floatValue;
  4237. double fc = double(ic);
  4238. // Don't check for float->double
  4239. // if( float(fc) != ic )
  4240. // {
  4241. // acCString str;
  4242. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  4243. // if( !isExplicit ) Warning(str, node);
  4244. // }
  4245. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4246. from->type.doubleValue = fc;
  4247. }
  4248. else if( from->type.dataType.IsEnumType() )
  4249. {
  4250. double fc = double(from->type.intValue);
  4251. if( int(fc) != from->type.intValue )
  4252. {
  4253. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4254. }
  4255. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4256. from->type.doubleValue = fc;
  4257. }
  4258. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4259. {
  4260. // Must properly convert value in case the from value is smaller
  4261. int ic;
  4262. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4263. ic = (signed char)from->type.byteValue;
  4264. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4265. ic = (short)from->type.wordValue;
  4266. else
  4267. ic = from->type.intValue;
  4268. double fc = double(ic);
  4269. if( int(fc) != ic )
  4270. {
  4271. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4272. }
  4273. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4274. from->type.doubleValue = fc;
  4275. }
  4276. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4277. {
  4278. double fc = double(asINT64(from->type.qwordValue));
  4279. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4280. {
  4281. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4282. }
  4283. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4284. from->type.doubleValue = fc;
  4285. }
  4286. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4287. {
  4288. // Must properly convert value in case the from value is smaller
  4289. unsigned int uic;
  4290. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4291. uic = from->type.byteValue;
  4292. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4293. uic = from->type.wordValue;
  4294. else
  4295. uic = from->type.dwordValue;
  4296. double fc = double(uic);
  4297. if( (unsigned int)(fc) != uic )
  4298. {
  4299. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4300. }
  4301. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4302. from->type.doubleValue = fc;
  4303. }
  4304. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4305. {
  4306. // TODO: MSVC6 doesn't permit UINT64 to double
  4307. double fc = double((signed)from->type.qwordValue);
  4308. if( asQWORD(fc) != from->type.qwordValue )
  4309. {
  4310. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4311. }
  4312. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4313. from->type.doubleValue = fc;
  4314. }
  4315. }
  4316. }
  4317. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  4318. {
  4319. // Implicit handle types should always be treated as handles in assignments
  4320. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4321. {
  4322. lctx->type.dataType.MakeHandle(true);
  4323. lctx->type.isExplicitHandle = true;
  4324. }
  4325. // If the left hand expression is a property accessor, then that should be used
  4326. // to do the assignment instead of the ordinary operator. The exception is when
  4327. // the property accessor is for a handle property, and the operation is a value
  4328. // assignment.
  4329. if( (lctx->property_get || lctx->property_set) &&
  4330. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  4331. {
  4332. if( op != ttAssignment )
  4333. {
  4334. // TODO: getset: We may actually be able to support this, if we can
  4335. // guarantee that the object reference will stay valid
  4336. // between the calls to the get and set accessors.
  4337. // Compound assignments are not allowed for properties
  4338. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  4339. return -1;
  4340. }
  4341. // It is not allowed to do a handle assignment on a property accessor that
  4342. // doesn't take a handle in the set accessor.
  4343. if( lctx->property_set &&
  4344. lctx->type.isExplicitHandle &&
  4345. !engine->scriptFunctions[lctx->property_set]->parameterTypes[0].IsObjectHandle() )
  4346. {
  4347. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  4348. return -1;
  4349. }
  4350. MergeExprBytecodeAndType(ctx, lctx);
  4351. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  4352. }
  4353. if( lctx->type.dataType.IsPrimitive() )
  4354. {
  4355. if( op != ttAssignment )
  4356. {
  4357. // Compute the operator before the assignment
  4358. asCTypeInfo lvalue = lctx->type;
  4359. if( lctx->type.isTemporary && !lctx->type.isVariable )
  4360. {
  4361. // The temporary variable must not be freed until the
  4362. // assignment has been performed. lvalue still holds
  4363. // the information about the temporary variable
  4364. lctx->type.isTemporary = false;
  4365. }
  4366. asSExprContext o(engine);
  4367. CompileOperator(opNode, lctx, rctx, &o);
  4368. MergeExprBytecode(rctx, &o);
  4369. rctx->type = o.type;
  4370. // Convert the rvalue to the right type and validate it
  4371. PrepareForAssignment(&lvalue.dataType, rctx, rexpr);
  4372. MergeExprBytecode(ctx, rctx);
  4373. lctx->type = lvalue;
  4374. // The lvalue continues the same, either it was a variable, or a reference in the register
  4375. }
  4376. else
  4377. {
  4378. // Convert the rvalue to the right type and validate it
  4379. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, lctx);
  4380. MergeExprBytecode(ctx, rctx);
  4381. MergeExprBytecode(ctx, lctx);
  4382. }
  4383. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4384. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4385. ctx->type = lctx->type;
  4386. }
  4387. else if( lctx->type.isExplicitHandle )
  4388. {
  4389. // Verify that the left hand value isn't a temporary variable
  4390. if( lctx->type.isTemporary )
  4391. {
  4392. Error(TXT_REF_IS_TEMP, lexpr);
  4393. return -1;
  4394. }
  4395. // Object handles don't have any compound assignment operators
  4396. if( op != ttAssignment )
  4397. {
  4398. asCString str;
  4399. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4400. Error(str.AddressOf(), lexpr);
  4401. return -1;
  4402. }
  4403. asCDataType dt = lctx->type.dataType;
  4404. dt.MakeReference(false);
  4405. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4406. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4407. {
  4408. asCString str;
  4409. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4410. Error(str.AddressOf(), rexpr);
  4411. return -1;
  4412. }
  4413. MergeExprBytecode(ctx, rctx);
  4414. MergeExprBytecode(ctx, lctx);
  4415. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4416. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4417. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4418. ctx->type = rctx->type;
  4419. }
  4420. else // if( lctx->type.dataType.IsObject() )
  4421. {
  4422. // Verify that the left hand value isn't a temporary variable
  4423. if( lctx->type.isTemporary )
  4424. {
  4425. Error(TXT_REF_IS_TEMP, lexpr);
  4426. return -1;
  4427. }
  4428. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4429. {
  4430. // Convert the handle to a object reference
  4431. asCDataType to;
  4432. to = lctx->type.dataType;
  4433. to.MakeHandle(false);
  4434. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  4435. }
  4436. // Check for overloaded assignment operator
  4437. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4438. {
  4439. // An overloaded assignment operator was found (or a compilation error occured)
  4440. return 0;
  4441. }
  4442. // No registered operator was found. In case the operation is a direct
  4443. // assignment and the rvalue is the same type as the lvalue, then we can
  4444. // still use the byte-for-byte copy to do the assignment
  4445. if( op != ttAssignment )
  4446. {
  4447. asCString str;
  4448. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4449. Error(str.AddressOf(), lexpr);
  4450. return -1;
  4451. }
  4452. // Implicitly convert the rvalue to the type of the lvalue
  4453. asCDataType dt = lctx->type.dataType;
  4454. dt.MakeReference(true);
  4455. dt.MakeReadOnly(true);
  4456. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4457. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4458. {
  4459. asCString str;
  4460. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4461. Error(str.AddressOf(), rexpr);
  4462. return -1;
  4463. }
  4464. MergeExprBytecode(ctx, rctx);
  4465. MergeExprBytecode(ctx, lctx);
  4466. if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
  4467. // TODO: optimize: Actually the reference can be pushed on the stack directly
  4468. // as the value allocated on the stack is guaranteed to be safe
  4469. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  4470. else
  4471. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4472. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4473. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4474. ctx->type = lctx->type;
  4475. }
  4476. return 0;
  4477. }
  4478. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  4479. {
  4480. asCScriptNode *lexpr = expr->firstChild;
  4481. if( lexpr->next )
  4482. {
  4483. if( globalExpression )
  4484. {
  4485. Error(TXT_ASSIGN_IN_GLOBAL_EXPR, expr);
  4486. ctx->type.SetDummy();
  4487. return -1;
  4488. }
  4489. // Compile the two expression terms
  4490. asSExprContext lctx(engine), rctx(engine);
  4491. int rr = CompileAssignment(lexpr->next->next, &rctx);
  4492. int lr = CompileCondition(lexpr, &lctx);
  4493. if( lr >= 0 && rr >= 0 )
  4494. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  4495. // Since the operands failed, the assignment was not computed
  4496. ctx->type.SetDummy();
  4497. return -1;
  4498. }
  4499. return CompileCondition(lexpr, ctx);
  4500. }
  4501. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  4502. {
  4503. asCTypeInfo ctype;
  4504. // Compile the conditional expression
  4505. asCScriptNode *cexpr = expr->firstChild;
  4506. if( cexpr->next )
  4507. {
  4508. //-------------------------------
  4509. // Compile the condition
  4510. asSExprContext e(engine);
  4511. int r = CompileExpression(cexpr, &e);
  4512. if( r < 0 )
  4513. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4514. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  4515. {
  4516. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  4517. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4518. }
  4519. ctype = e.type;
  4520. ProcessPropertyGetAccessor(&e, cexpr);
  4521. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  4522. ProcessDeferredParams(&e);
  4523. //-------------------------------
  4524. // Compile the left expression
  4525. asSExprContext le(engine);
  4526. int lr = CompileAssignment(cexpr->next, &le);
  4527. //-------------------------------
  4528. // Compile the right expression
  4529. asSExprContext re(engine);
  4530. int rr = CompileAssignment(cexpr->next->next, &re);
  4531. if( lr >= 0 && rr >= 0 )
  4532. {
  4533. ProcessPropertyGetAccessor(&le, cexpr->next);
  4534. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  4535. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  4536. // Allow a 0 in the first case to be implicitly converted to the second type
  4537. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  4538. {
  4539. asCDataType to = re.type.dataType;
  4540. to.MakeReference(false);
  4541. to.MakeReadOnly(true);
  4542. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  4543. }
  4544. //---------------------------------
  4545. // Output the byte code
  4546. int afterLabel = nextLabel++;
  4547. int elseLabel = nextLabel++;
  4548. // If left expression is void, then we don't need to store the result
  4549. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  4550. {
  4551. // Put the code for the condition expression on the output
  4552. MergeExprBytecode(ctx, &e);
  4553. // Added the branch decision
  4554. ctx->type = e.type;
  4555. ConvertToVariable(ctx);
  4556. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4557. ctx->bc.Instr(asBC_ClrHi);
  4558. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4559. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4560. // Add the left expression
  4561. MergeExprBytecode(ctx, &le);
  4562. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4563. // Add the right expression
  4564. ctx->bc.Label((short)elseLabel);
  4565. MergeExprBytecode(ctx, &re);
  4566. ctx->bc.Label((short)afterLabel);
  4567. // Make sure both expressions have the same type
  4568. if( le.type.dataType != re.type.dataType )
  4569. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4570. // Set the type of the result
  4571. ctx->type = le.type;
  4572. }
  4573. else
  4574. {
  4575. // Allocate temporary variable and copy the result to that one
  4576. asCTypeInfo temp;
  4577. temp = le.type;
  4578. temp.dataType.MakeReference(false);
  4579. temp.dataType.MakeReadOnly(false);
  4580. // Make sure the variable isn't used in the initial expression
  4581. asCArray<int> vars;
  4582. e.bc.GetVarsUsed(vars);
  4583. int offset = AllocateVariableNotIn(temp.dataType, true, &vars);
  4584. temp.SetVariable(temp.dataType, offset, true);
  4585. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  4586. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  4587. // Put the code for the condition expression on the output
  4588. MergeExprBytecode(ctx, &e);
  4589. // Add the branch decision
  4590. ctx->type = e.type;
  4591. ConvertToVariable(ctx);
  4592. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4593. ctx->bc.Instr(asBC_ClrHi);
  4594. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4595. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4596. // Assign the result of the left expression to the temporary variable
  4597. asCTypeInfo rtemp;
  4598. rtemp = temp;
  4599. if( rtemp.dataType.IsObjectHandle() )
  4600. rtemp.isExplicitHandle = true;
  4601. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next);
  4602. MergeExprBytecode(ctx, &le);
  4603. if( !rtemp.dataType.IsPrimitive() )
  4604. {
  4605. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4606. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4607. }
  4608. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  4609. if( !rtemp.dataType.IsPrimitive() )
  4610. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4611. // Release the old temporary variable
  4612. ReleaseTemporaryVariable(le.type, &ctx->bc);
  4613. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4614. // Start of the right expression
  4615. ctx->bc.Label((short)elseLabel);
  4616. // Copy the result to the same temporary variable
  4617. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next);
  4618. MergeExprBytecode(ctx, &re);
  4619. if( !rtemp.dataType.IsPrimitive() )
  4620. {
  4621. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4622. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4623. }
  4624. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  4625. if( !rtemp.dataType.IsPrimitive() )
  4626. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4627. // Release the old temporary variable
  4628. ReleaseTemporaryVariable(re.type, &ctx->bc);
  4629. ctx->bc.Label((short)afterLabel);
  4630. // Make sure both expressions have the same type
  4631. if( le.type.dataType != re.type.dataType )
  4632. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4633. // Set the temporary variable as output
  4634. ctx->type = rtemp;
  4635. ctx->type.isExplicitHandle = isExplicitHandle;
  4636. if( !ctx->type.dataType.IsPrimitive() )
  4637. {
  4638. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4639. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4640. }
  4641. // Make sure the output isn't marked as being a literal constant
  4642. ctx->type.isConstant = false;
  4643. }
  4644. }
  4645. else
  4646. {
  4647. ctx->type.SetDummy();
  4648. return -1;
  4649. }
  4650. }
  4651. else
  4652. return CompileExpression(cexpr, ctx);
  4653. return 0;
  4654. }
  4655. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  4656. {
  4657. asASSERT(expr->nodeType == snExpression);
  4658. // Count the nodes
  4659. int count = 0;
  4660. asCScriptNode *node = expr->firstChild;
  4661. while( node )
  4662. {
  4663. count++;
  4664. node = node->next;
  4665. }
  4666. // Convert to polish post fix, i.e: a+b => ab+
  4667. asCArray<asCScriptNode *> stack(count);
  4668. asCArray<asCScriptNode *> stack2(count);
  4669. asCArray<asCScriptNode *> postfix(count);
  4670. node = expr->firstChild;
  4671. while( node )
  4672. {
  4673. int precedence = GetPrecedence(node);
  4674. while( stack.GetLength() > 0 &&
  4675. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  4676. stack2.PushLast(stack.PopLast());
  4677. stack.PushLast(node);
  4678. node = node->next;
  4679. }
  4680. while( stack.GetLength() > 0 )
  4681. stack2.PushLast(stack.PopLast());
  4682. // We need to swap operands so that the left
  4683. // operand is always computed before the right
  4684. SwapPostFixOperands(stack2, postfix);
  4685. // Compile the postfix formatted expression
  4686. return CompilePostFixExpression(&postfix, ctx);
  4687. }
  4688. void asCCompiler::SwapPostFixOperands(asCArray<asCScriptNode *> &postfix, asCArray<asCScriptNode *> &target)
  4689. {
  4690. if( postfix.GetLength() == 0 ) return;
  4691. asCScriptNode *node = postfix.PopLast();
  4692. if( node->nodeType == snExprTerm )
  4693. {
  4694. target.PushLast(node);
  4695. return;
  4696. }
  4697. SwapPostFixOperands(postfix, target);
  4698. SwapPostFixOperands(postfix, target);
  4699. target.PushLast(node);
  4700. }
  4701. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  4702. {
  4703. // Shouldn't send any byte code
  4704. asASSERT(ctx->bc.GetLastInstr() == -1);
  4705. // Set the context to a dummy type to avoid further
  4706. // errors in case the expression fails to compile
  4707. ctx->type.SetDummy();
  4708. // Pop the last node
  4709. asCScriptNode *node = postfix->PopLast();
  4710. ctx->exprNode = node;
  4711. // If term, compile the term
  4712. if( node->nodeType == snExprTerm )
  4713. return CompileExpressionTerm(node, ctx);
  4714. // Compile the two expression terms
  4715. asSExprContext r(engine), l(engine);
  4716. int ret;
  4717. ret = CompilePostFixExpression(postfix, &l); if( ret < 0 ) return ret;
  4718. ret = CompilePostFixExpression(postfix, &r); if( ret < 0 ) return ret;
  4719. // Compile the operation
  4720. return CompileOperator(node, &l, &r, ctx);
  4721. }
  4722. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  4723. {
  4724. // Shouldn't send any byte code
  4725. asASSERT(ctx->bc.GetLastInstr() == -1);
  4726. // Set the type as a dummy by default, in case of any compiler errors
  4727. ctx->type.SetDummy();
  4728. // Compile the value node
  4729. asCScriptNode *vnode = node->firstChild;
  4730. while( vnode->nodeType != snExprValue )
  4731. vnode = vnode->next;
  4732. asSExprContext v(engine);
  4733. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  4734. // Compile post fix operators
  4735. asCScriptNode *pnode = vnode->next;
  4736. while( pnode )
  4737. {
  4738. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  4739. pnode = pnode->next;
  4740. }
  4741. // Compile pre fix operators
  4742. pnode = vnode->prev;
  4743. while( pnode )
  4744. {
  4745. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  4746. pnode = pnode->prev;
  4747. }
  4748. // Return the byte code and final type description
  4749. MergeExprBytecodeAndType(ctx, &v);
  4750. return 0;
  4751. }
  4752. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, asCObjectType *objType)
  4753. {
  4754. bool found = false;
  4755. // It is a local variable or parameter?
  4756. sVariable *v = 0;
  4757. if( scope == "" && !objType )
  4758. v = variables->GetVariable(name.AddressOf());
  4759. if( v )
  4760. {
  4761. found = true;
  4762. if( v->isPureConstant )
  4763. ctx->type.SetConstantQW(v->type, v->constantValue);
  4764. else if( v->type.IsPrimitive() )
  4765. {
  4766. if( v->type.IsReference() )
  4767. {
  4768. // Copy the reference into the register
  4769. #if AS_PTR_SIZE == 1
  4770. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)v->stackOffset);
  4771. #else
  4772. ctx->bc.InstrSHORT(asBC_CpyVtoR8, (short)v->stackOffset);
  4773. #endif
  4774. ctx->type.Set(v->type);
  4775. }
  4776. else
  4777. ctx->type.SetVariable(v->type, v->stackOffset, false);
  4778. }
  4779. else
  4780. {
  4781. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  4782. ctx->type.SetVariable(v->type, v->stackOffset, false);
  4783. // If the variable is allocated on the heap we have a reference,
  4784. // otherwise the actual object pointer is pushed on the stack.
  4785. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  4786. // Implicitly dereference handle parameters sent by reference
  4787. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  4788. ctx->bc.Instr(asBC_RDSPTR);
  4789. }
  4790. }
  4791. // Is it a class member?
  4792. if( !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  4793. {
  4794. if( name == THIS_TOKEN && !objType )
  4795. {
  4796. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  4797. // The object pointer is located at stack position 0
  4798. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4799. ctx->type.SetVariable(dt, 0, false);
  4800. ctx->type.dataType.MakeReference(true);
  4801. found = true;
  4802. }
  4803. if( !found )
  4804. {
  4805. // See if there are any matching property accessors
  4806. asSExprContext access(engine);
  4807. if( objType )
  4808. access.type.Set(asCDataType::CreateObject(objType, false));
  4809. else
  4810. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  4811. access.type.dataType.MakeReference(true);
  4812. int r = 0;
  4813. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  4814. {
  4815. // This is an index access, check if there is a property accessor that takes an index arg
  4816. asSExprContext dummyArg(engine);
  4817. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  4818. }
  4819. if( r == 0 )
  4820. {
  4821. // Normal property access
  4822. r = FindPropertyAccessor(name, &access, errNode);
  4823. }
  4824. if( r < 0 ) return -1;
  4825. if( access.property_get || access.property_set )
  4826. {
  4827. if( !objType )
  4828. {
  4829. // Prepare the bytecode for the member access
  4830. // This is only done when accessing through the implicit this pointer
  4831. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4832. }
  4833. MergeExprBytecodeAndType(ctx, &access);
  4834. found = true;
  4835. }
  4836. }
  4837. if( !found )
  4838. {
  4839. asCDataType dt;
  4840. if( objType )
  4841. dt = asCDataType::CreateObject(objType, false);
  4842. else
  4843. dt = asCDataType::CreateObject(outFunc->objectType, false);
  4844. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  4845. if( prop )
  4846. {
  4847. if( !objType )
  4848. {
  4849. // The object pointer is located at stack position 0
  4850. // This is only done when accessing through the implicit this pointer
  4851. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4852. ctx->type.SetVariable(dt, 0, false);
  4853. ctx->type.dataType.MakeReference(true);
  4854. Dereference(ctx, true);
  4855. }
  4856. // TODO: This is the same as what is in CompileExpressionPostOp
  4857. // Put the offset on the stack
  4858. ctx->bc.InstrSHORT_DW(asBC_ADDSi, prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  4859. if( prop->type.IsReference() )
  4860. ctx->bc.Instr(asBC_RDSPTR);
  4861. // Reference to primitive must be stored in the temp register
  4862. if( prop->type.IsPrimitive() )
  4863. {
  4864. // TODO: optimize: The ADD offset command should store the reference in the register directly
  4865. ctx->bc.Instr(asBC_PopRPtr);
  4866. }
  4867. // Set the new type (keeping info about temp variable)
  4868. ctx->type.dataType = prop->type;
  4869. ctx->type.dataType.MakeReference(true);
  4870. ctx->type.isVariable = false;
  4871. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  4872. {
  4873. // Objects that are members are not references
  4874. ctx->type.dataType.MakeReference(false);
  4875. }
  4876. // If the object reference is const, the property will also be const
  4877. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  4878. found = true;
  4879. }
  4880. }
  4881. }
  4882. // Is it a global property?
  4883. if( !found && (scope == "" || scope == "::") && !objType )
  4884. {
  4885. // See if there are any matching global property accessors
  4886. asSExprContext access(engine);
  4887. int r = 0;
  4888. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  4889. {
  4890. // This is an index access, check if there is a property accessor that takes an index arg
  4891. asSExprContext dummyArg(engine);
  4892. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  4893. }
  4894. if( r == 0 )
  4895. {
  4896. // Normal property access
  4897. r = FindPropertyAccessor(name, &access, errNode);
  4898. }
  4899. if( r < 0 ) return -1;
  4900. if( access.property_get || access.property_set )
  4901. {
  4902. // Prepare the bytecode for the function call
  4903. MergeExprBytecodeAndType(ctx, &access);
  4904. found = true;
  4905. }
  4906. // See if there is any matching global property
  4907. if( !found )
  4908. {
  4909. bool isCompiled = true;
  4910. bool isPureConstant = false;
  4911. asQWORD constantValue;
  4912. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), &isCompiled, &isPureConstant, &constantValue);
  4913. if( prop )
  4914. {
  4915. found = true;
  4916. // Verify that the global property has been compiled already
  4917. if( isCompiled )
  4918. {
  4919. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4920. {
  4921. ctx->type.dataType.MakeHandle(true);
  4922. ctx->type.isExplicitHandle = true;
  4923. }
  4924. // If the global property is a pure constant
  4925. // we can allow the compiler to optimize it. Pure
  4926. // constants are global constant variables that were
  4927. // initialized by literal constants.
  4928. if( isPureConstant )
  4929. ctx->type.SetConstantQW(prop->type, constantValue);
  4930. else
  4931. {
  4932. ctx->type.Set(prop->type);
  4933. ctx->type.dataType.MakeReference(true);
  4934. if( ctx->type.dataType.IsPrimitive() )
  4935. {
  4936. // Load the address of the variable into the register
  4937. ctx->bc.InstrPTR(asBC_LDG, engine->globalProperties[prop->id]->GetAddressOfValue());
  4938. }
  4939. else
  4940. {
  4941. // Push the address of the variable on the stack
  4942. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[prop->id]->GetAddressOfValue());
  4943. // If the object is a value type, then we must validate the existance,
  4944. // as it could potentially be accessed before it is initialized.
  4945. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
  4946. !ctx->type.dataType.IsObjectHandle() )
  4947. {
  4948. // TODO: optimize: This is not necessary for application registered properties
  4949. ctx->bc.Instr(asBC_ChkRefS);
  4950. }
  4951. }
  4952. }
  4953. }
  4954. else
  4955. {
  4956. asCString str;
  4957. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  4958. Error(str.AddressOf(), errNode);
  4959. return -1;
  4960. }
  4961. }
  4962. }
  4963. }
  4964. // Is it the name of a global function?
  4965. if( !noFunction && !found && (scope == "" || scope == "::") && !objType )
  4966. {
  4967. asCArray<int> funcs;
  4968. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  4969. if( funcs.GetLength() > 1 )
  4970. {
  4971. // TODO: funcdef: If multiple functions are found, then the compiler should defer the decision
  4972. // to which one it should use until the value is actually used.
  4973. //
  4974. // - assigning the function pointer to a variable
  4975. // - performing an explicit cast
  4976. // - passing the function pointer to a function as parameter
  4977. asCString str;
  4978. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, name.AddressOf());
  4979. Error(str.AddressOf(), errNode);
  4980. return -1;
  4981. }
  4982. else if( funcs.GetLength() == 1 )
  4983. {
  4984. found = true;
  4985. // Push the function pointer on the stack
  4986. ctx->bc.InstrPTR(asBC_FuncPtr, engine->scriptFunctions[funcs[0]]);
  4987. ctx->type.Set(asCDataType::CreateFuncDef(engine->scriptFunctions[funcs[0]]));
  4988. }
  4989. }
  4990. // Is it an enum value?
  4991. if( !found && !objType )
  4992. {
  4993. asCObjectType *scopeType = 0;
  4994. if( scope != "" )
  4995. {
  4996. // resolve the type before the scope
  4997. scopeType = builder->GetObjectType( scope.AddressOf() );
  4998. }
  4999. asDWORD value = 0;
  5000. asCDataType dt;
  5001. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  5002. {
  5003. // scoped enum value found
  5004. found = true;
  5005. }
  5006. else if( scope == "" && !engine->ep.requireEnumScope )
  5007. {
  5008. // look for the enum value with no namespace
  5009. int e = builder->GetEnumValue(name.AddressOf(), dt, value);
  5010. if( e )
  5011. {
  5012. found = true;
  5013. if( e == 2 )
  5014. {
  5015. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  5016. }
  5017. }
  5018. }
  5019. if( found )
  5020. {
  5021. // an enum value was resolved
  5022. ctx->type.SetConstantDW(dt, value);
  5023. }
  5024. }
  5025. // The name doesn't match any variable
  5026. if( !found )
  5027. {
  5028. // Give dummy value
  5029. ctx->type.SetDummy();
  5030. if( !isOptional )
  5031. {
  5032. // Prepend the scope to the name for the error message
  5033. asCString ename;
  5034. if( scope != "" && scope != "::" )
  5035. ename = scope + "::";
  5036. else
  5037. ename = scope;
  5038. ename += name;
  5039. asCString str;
  5040. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  5041. Error(str.AddressOf(), errNode);
  5042. // Declare the variable now so that it will not be reported again
  5043. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  5044. // Mark the variable as initialized so that the user will not be bother by it again
  5045. sVariable *v = variables->GetVariable(name.AddressOf());
  5046. asASSERT(v);
  5047. if( v ) v->isInitialized = true;
  5048. }
  5049. // Return -1 to signal that the variable wasn't found
  5050. return -1;
  5051. }
  5052. return 0;
  5053. }
  5054. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  5055. {
  5056. // Shouldn't receive any byte code
  5057. asASSERT(ctx->bc.GetLastInstr() == -1);
  5058. asCScriptNode *vnode = node->firstChild;
  5059. ctx->exprNode = vnode;
  5060. if( vnode->nodeType == snVariableAccess )
  5061. {
  5062. // Determine the scope resolution of the variable
  5063. asCString scope = GetScopeFromNode(vnode);
  5064. // Determine the name of the variable
  5065. vnode = vnode->lastChild;
  5066. asASSERT(vnode->nodeType == snIdentifier );
  5067. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  5068. return CompileVariableAccess(name, scope, ctx, node);
  5069. }
  5070. else if( vnode->nodeType == snConstant )
  5071. {
  5072. if( vnode->tokenType == ttIntConstant )
  5073. {
  5074. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5075. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  5076. // Do we need 64 bits?
  5077. if( val>>32 )
  5078. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5079. else
  5080. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5081. }
  5082. else if( vnode->tokenType == ttBitsConstant )
  5083. {
  5084. asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
  5085. // TODO: Check for overflow
  5086. asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
  5087. // Do we need 64 bits?
  5088. if( val>>32 )
  5089. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5090. else
  5091. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5092. }
  5093. else if( vnode->tokenType == ttFloatConstant )
  5094. {
  5095. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5096. // TODO: Check for overflow
  5097. size_t numScanned;
  5098. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  5099. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  5100. // Urho3D: fix assert if always using floats
  5101. #ifdef AS_USE_DOUBLE_AS_FLOAT
  5102. asASSERT((numScanned == vnode->tokenLength - 1) || (numScanned == vnode->tokenLength));
  5103. #else
  5104. asASSERT(numScanned == vnode->tokenLength - 1);
  5105. #endif
  5106. }
  5107. else if( vnode->tokenType == ttDoubleConstant )
  5108. {
  5109. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5110. // TODO: Check for overflow
  5111. size_t numScanned;
  5112. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  5113. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  5114. asASSERT(numScanned == vnode->tokenLength);
  5115. }
  5116. else if( vnode->tokenType == ttTrue ||
  5117. vnode->tokenType == ttFalse )
  5118. {
  5119. #if AS_SIZEOF_BOOL == 1
  5120. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5121. #else
  5122. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5123. #endif
  5124. }
  5125. else if( vnode->tokenType == ttStringConstant ||
  5126. vnode->tokenType == ttMultilineStringConstant ||
  5127. vnode->tokenType == ttHeredocStringConstant )
  5128. {
  5129. asCString str;
  5130. asCScriptNode *snode = vnode->firstChild;
  5131. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  5132. {
  5133. // Treat the single quoted string as a single character literal
  5134. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5135. asDWORD val = 0;
  5136. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  5137. {
  5138. // This is the start of a UTF8 encoded character. We need to decode it
  5139. val = asStringDecodeUTF8(str.AddressOf(), 0);
  5140. if( val == (asDWORD)-1 )
  5141. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5142. }
  5143. else
  5144. {
  5145. val = ProcessStringConstant(str, snode);
  5146. if( val == (asDWORD)-1 )
  5147. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5148. }
  5149. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  5150. }
  5151. else
  5152. {
  5153. // Process the string constants
  5154. while( snode )
  5155. {
  5156. asCString cat;
  5157. if( snode->tokenType == ttStringConstant )
  5158. {
  5159. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5160. ProcessStringConstant(cat, snode);
  5161. }
  5162. else if( snode->tokenType == ttMultilineStringConstant )
  5163. {
  5164. if( !engine->ep.allowMultilineStrings )
  5165. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  5166. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5167. ProcessStringConstant(cat, snode);
  5168. }
  5169. else if( snode->tokenType == ttHeredocStringConstant )
  5170. {
  5171. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  5172. ProcessHeredocStringConstant(cat, snode);
  5173. }
  5174. str += cat;
  5175. snode = snode->next;
  5176. }
  5177. // Call the string factory function to create a string object
  5178. asCScriptFunction *descr = engine->stringFactory;
  5179. if( descr == 0 )
  5180. {
  5181. // Error
  5182. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  5183. // Give dummy value
  5184. ctx->type.SetDummy();
  5185. return -1;
  5186. }
  5187. else
  5188. {
  5189. // Register the constant string with the engine
  5190. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  5191. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  5192. PerformFunctionCall(descr->id, ctx);
  5193. }
  5194. }
  5195. }
  5196. else if( vnode->tokenType == ttNull )
  5197. {
  5198. #ifndef AS_64BIT_PTR
  5199. ctx->bc.InstrDWORD(asBC_PshC4, 0);
  5200. #else
  5201. ctx->bc.InstrQWORD(asBC_PshC8, 0);
  5202. #endif
  5203. ctx->type.SetNullConstant();
  5204. }
  5205. else
  5206. asASSERT(false);
  5207. }
  5208. else if( vnode->nodeType == snFunctionCall )
  5209. {
  5210. bool found = false;
  5211. // Determine the scope resolution
  5212. asCString scope = GetScopeFromNode(vnode);
  5213. if( outFunc && outFunc->objectType && scope != "::" )
  5214. {
  5215. // TODO: funcdef: There may be a local variable of a function type with the same name
  5216. // Check if a class method is being called
  5217. asCScriptNode *nm = vnode->lastChild->prev;
  5218. asCString name;
  5219. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  5220. asCArray<int> funcs;
  5221. // If we're compiling a constructor and the name of the function called
  5222. // is 'super' then the base class' constructor is being called.
  5223. // super cannot be called from another scope, i.e. must not be prefixed
  5224. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  5225. {
  5226. // Actually it is the base class' constructor that is being called,
  5227. // but as we won't use the actual function ids here we can take the
  5228. // object's own constructors and avoid the need to check if the
  5229. // object actually derives from any other class
  5230. funcs = outFunc->objectType->beh.constructors;
  5231. // Must not allow calling constructors multiple times
  5232. if( continueLabels.GetLength() > 0 )
  5233. {
  5234. // If a continue label is set we are in a loop
  5235. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, vnode);
  5236. }
  5237. else if( breakLabels.GetLength() > 0 )
  5238. {
  5239. // TODO: inheritance: Should eventually allow constructors in switch statements
  5240. // If a break label is set we are either in a loop or a switch statements
  5241. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, vnode);
  5242. }
  5243. else if( m_isConstructorCalled )
  5244. {
  5245. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, vnode);
  5246. }
  5247. m_isConstructorCalled = true;
  5248. }
  5249. else
  5250. builder->GetObjectMethodDescriptions(name.AddressOf(), outFunc->objectType, funcs, false);
  5251. if( funcs.GetLength() )
  5252. {
  5253. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, false);
  5254. // The object pointer is located at stack position 0
  5255. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5256. ctx->type.SetVariable(dt, 0, false);
  5257. ctx->type.dataType.MakeReference(true);
  5258. // TODO: optimize: This adds a CHKREF. Is that really necessary?
  5259. Dereference(ctx, true);
  5260. CompileFunctionCall(vnode, ctx, outFunc->objectType, false, scope);
  5261. found = true;
  5262. }
  5263. }
  5264. if( !found )
  5265. CompileFunctionCall(vnode, ctx, 0, false, scope);
  5266. }
  5267. else if( vnode->nodeType == snConstructCall )
  5268. {
  5269. CompileConstructCall(vnode, ctx);
  5270. }
  5271. else if( vnode->nodeType == snAssignment )
  5272. {
  5273. asSExprContext e(engine);
  5274. int r = CompileAssignment(vnode, &e);
  5275. if( r < 0 )
  5276. {
  5277. ctx->type.SetDummy();
  5278. return r;
  5279. }
  5280. MergeExprBytecodeAndType(ctx, &e);
  5281. }
  5282. else if( vnode->nodeType == snCast )
  5283. {
  5284. // Implement the cast operator
  5285. CompileConversion(vnode, ctx);
  5286. }
  5287. else
  5288. asASSERT(false);
  5289. return 0;
  5290. }
  5291. asCString asCCompiler::GetScopeFromNode(asCScriptNode *node)
  5292. {
  5293. asCString scope;
  5294. asCScriptNode *sn = node->firstChild;
  5295. if( sn->tokenType == ttScope )
  5296. {
  5297. // Global scope
  5298. scope = "::";
  5299. sn = sn->next;
  5300. }
  5301. else if( sn->next && sn->next->tokenType == ttScope )
  5302. {
  5303. scope.Assign(&script->code[sn->tokenPos], sn->tokenLength);
  5304. sn = sn->next->next;
  5305. }
  5306. if( scope != "" )
  5307. {
  5308. // We don't support multiple levels of scope yet
  5309. if( sn->next && sn->next->tokenType == ttScope )
  5310. {
  5311. Error(TXT_INVALID_SCOPE, sn->next);
  5312. }
  5313. }
  5314. return scope;
  5315. }
  5316. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  5317. {
  5318. int charLiteral = -1;
  5319. // Process escape sequences
  5320. asCArray<char> str((int)cstr.GetLength());
  5321. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  5322. {
  5323. #ifdef AS_DOUBLEBYTE_CHARSET
  5324. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  5325. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  5326. {
  5327. // This is the lead character of a double byte character
  5328. // include the trail character without checking it's value.
  5329. str.PushLast(cstr[n]);
  5330. n++;
  5331. str.PushLast(cstr[n]);
  5332. continue;
  5333. }
  5334. #endif
  5335. asUINT val;
  5336. if( processEscapeSequences && cstr[n] == '\\' )
  5337. {
  5338. ++n;
  5339. if( n == cstr.GetLength() )
  5340. {
  5341. if( charLiteral == -1 ) charLiteral = 0;
  5342. return charLiteral;
  5343. }
  5344. // TODO: Consider deprecating use of hexadecimal escape sequences,
  5345. // as they do not guarantee proper unicode sequences
  5346. if( cstr[n] == 'x' || cstr[n] == 'X' )
  5347. {
  5348. ++n;
  5349. if( n == cstr.GetLength() ) break;
  5350. val = 0;
  5351. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  5352. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  5353. {
  5354. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5355. val = val*16 + cstr[n] - '0';
  5356. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5357. val = val*16 + cstr[n] - 'a' + 10;
  5358. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5359. val = val*16 + cstr[n] - 'A' + 10;
  5360. else
  5361. break;
  5362. }
  5363. // Rewind one, since the loop will increment it again
  5364. n--;
  5365. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  5366. if( engine->ep.stringEncoding == 0 )
  5367. {
  5368. str.PushLast(val);
  5369. }
  5370. else
  5371. {
  5372. #ifndef AS_BIG_ENDIAN
  5373. str.PushLast(val);
  5374. str.PushLast(val>>8);
  5375. #else
  5376. str.PushLast(val>>8);
  5377. str.PushLast(val);
  5378. #endif
  5379. }
  5380. if( charLiteral == -1 ) charLiteral = val;
  5381. continue;
  5382. }
  5383. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  5384. {
  5385. // \u expects 4 hex digits
  5386. // \U expects 8 hex digits
  5387. bool expect2 = cstr[n] == 'u';
  5388. int c = expect2 ? 4 : 8;
  5389. val = 0;
  5390. for( ; c > 0; c-- )
  5391. {
  5392. ++n;
  5393. if( n == cstr.GetLength() ) break;
  5394. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5395. val = val*16 + cstr[n] - '0';
  5396. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5397. val = val*16 + cstr[n] - 'a' + 10;
  5398. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5399. val = val*16 + cstr[n] - 'A' + 10;
  5400. else
  5401. break;
  5402. }
  5403. if( c != 0 )
  5404. {
  5405. // Give warning about invalid code point
  5406. // TODO: Need code position for warning
  5407. asCString msg;
  5408. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  5409. Warning(msg.AddressOf(), node);
  5410. continue;
  5411. }
  5412. }
  5413. else
  5414. {
  5415. if( cstr[n] == '"' )
  5416. val = '"';
  5417. else if( cstr[n] == '\'' )
  5418. val = '\'';
  5419. else if( cstr[n] == 'n' )
  5420. val = '\n';
  5421. else if( cstr[n] == 'r' )
  5422. val = '\r';
  5423. else if( cstr[n] == 't' )
  5424. val = '\t';
  5425. else if( cstr[n] == '0' )
  5426. val = '\0';
  5427. else if( cstr[n] == '\\' )
  5428. val = '\\';
  5429. else
  5430. {
  5431. // Invalid escape sequence
  5432. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  5433. continue;
  5434. }
  5435. }
  5436. }
  5437. else
  5438. {
  5439. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  5440. {
  5441. unsigned int len;
  5442. val = asStringDecodeUTF8(&cstr[n], &len);
  5443. if( val == 0xFFFFFFFF || len < 0 )
  5444. {
  5445. // Incorrect UTF8 encoding. Use only the first byte
  5446. // TODO: Need code position for warning
  5447. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  5448. val = (unsigned char)cstr[n];
  5449. }
  5450. else
  5451. n += len-1;
  5452. }
  5453. else
  5454. val = (unsigned char)cstr[n];
  5455. }
  5456. // Add the character to the final string
  5457. char encodedValue[5];
  5458. int len;
  5459. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  5460. {
  5461. // Convert to UTF8 encoded
  5462. len = asStringEncodeUTF8(val, encodedValue);
  5463. }
  5464. else if( engine->ep.stringEncoding == 1 )
  5465. {
  5466. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  5467. len = asStringEncodeUTF16(val, encodedValue);
  5468. }
  5469. else
  5470. {
  5471. // Do not convert ASCII characters
  5472. encodedValue[0] = val;
  5473. len = 1;
  5474. }
  5475. if( len < 0 )
  5476. {
  5477. // Give warning about invalid code point
  5478. // TODO: Need code position for warning
  5479. Warning(TXT_INVALID_UNICODE_VALUE, node);
  5480. }
  5481. else
  5482. {
  5483. // Add the encoded value to the final string
  5484. str.Concatenate(encodedValue, len);
  5485. if( charLiteral == -1 ) charLiteral = val;
  5486. }
  5487. }
  5488. cstr.Assign(str.AddressOf(), str.GetLength());
  5489. return charLiteral;
  5490. }
  5491. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  5492. {
  5493. // Remove first line if it only contains whitespace
  5494. int start;
  5495. for( start = 0; start < (int)str.GetLength(); start++ )
  5496. {
  5497. if( str[start] == '\n' )
  5498. {
  5499. // Remove the linebreak as well
  5500. start++;
  5501. break;
  5502. }
  5503. if( str[start] != ' ' &&
  5504. str[start] != '\t' &&
  5505. str[start] != '\r' )
  5506. {
  5507. // Don't remove anything
  5508. start = 0;
  5509. break;
  5510. }
  5511. }
  5512. // Remove last line break and the line after that if it only contains whitespaces
  5513. int end;
  5514. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  5515. {
  5516. if( str[end] == '\n' )
  5517. break;
  5518. if( str[end] != ' ' &&
  5519. str[end] != '\t' &&
  5520. str[end] != '\r' )
  5521. {
  5522. // Don't remove anything
  5523. end = (int)str.GetLength();
  5524. break;
  5525. }
  5526. }
  5527. if( end < 0 ) end = 0;
  5528. asCString tmp;
  5529. if( end > start )
  5530. tmp.Assign(&str[start], end-start);
  5531. ProcessStringConstant(tmp, node, false);
  5532. str = tmp;
  5533. }
  5534. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  5535. {
  5536. asSExprContext expr(engine);
  5537. asCDataType to;
  5538. bool anyErrors = false;
  5539. EImplicitConv convType;
  5540. if( node->nodeType == snConstructCall )
  5541. {
  5542. convType = asIC_EXPLICIT_VAL_CAST;
  5543. // Verify that there is only one argument
  5544. if( node->lastChild->firstChild == 0 ||
  5545. node->lastChild->firstChild != node->lastChild->lastChild )
  5546. {
  5547. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  5548. expr.type.SetDummy();
  5549. anyErrors = true;
  5550. }
  5551. else
  5552. {
  5553. // Compile the expression
  5554. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  5555. if( r < 0 )
  5556. anyErrors = true;
  5557. }
  5558. // Determine the requested type
  5559. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5560. to.MakeReadOnly(true); // Default to const
  5561. asASSERT(to.IsPrimitive());
  5562. }
  5563. else
  5564. {
  5565. convType = asIC_EXPLICIT_REF_CAST;
  5566. // Compile the expression
  5567. int r = CompileAssignment(node->lastChild, &expr);
  5568. if( r < 0 )
  5569. anyErrors = true;
  5570. else
  5571. {
  5572. // Determine the requested type
  5573. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5574. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  5575. // If the type support object handles, then use it
  5576. if( to.SupportHandles() )
  5577. {
  5578. to.MakeHandle(true);
  5579. }
  5580. else if( !to.IsObjectHandle() )
  5581. {
  5582. // The cast<type> operator can only be used for reference casts
  5583. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  5584. anyErrors = true;
  5585. }
  5586. }
  5587. }
  5588. if( anyErrors )
  5589. {
  5590. // Assume that the error can be fixed and allow the compilation to continue
  5591. ctx->type.SetConstantDW(to, 0);
  5592. return;
  5593. }
  5594. ProcessPropertyGetAccessor(&expr, node);
  5595. // We don't want a reference
  5596. if( expr.type.dataType.IsReference() )
  5597. {
  5598. if( expr.type.dataType.IsObject() )
  5599. Dereference(&expr, true);
  5600. else
  5601. ConvertToVariable(&expr);
  5602. }
  5603. ImplicitConversion(&expr, to, node, convType);
  5604. IsVariableInitialized(&expr.type, node);
  5605. // If no type conversion is really tried ignore it
  5606. if( to == expr.type.dataType )
  5607. {
  5608. // This will keep information about constant type
  5609. MergeExprBytecode(ctx, &expr);
  5610. ctx->type = expr.type;
  5611. return;
  5612. }
  5613. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  5614. {
  5615. MergeExprBytecode(ctx, &expr);
  5616. ctx->type = expr.type;
  5617. ctx->type.dataType.MakeReadOnly(true);
  5618. return;
  5619. }
  5620. // The implicit conversion already does most of the conversions permitted,
  5621. // here we'll only treat those conversions that require an explicit cast.
  5622. bool conversionOK = false;
  5623. if( !expr.type.isConstant )
  5624. {
  5625. if( !expr.type.dataType.IsObject() )
  5626. ConvertToTempVariable(&expr);
  5627. if( to.IsObjectHandle() &&
  5628. expr.type.dataType.IsObjectHandle() &&
  5629. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  5630. {
  5631. conversionOK = CompileRefCast(&expr, to, true, node);
  5632. MergeExprBytecode(ctx, &expr);
  5633. ctx->type = expr.type;
  5634. }
  5635. }
  5636. if( conversionOK )
  5637. return;
  5638. // Conversion not available
  5639. ctx->type.SetDummy();
  5640. asCString strTo, strFrom;
  5641. strTo = to.Format();
  5642. strFrom = expr.type.dataType.Format();
  5643. asCString msg;
  5644. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  5645. Error(msg.AddressOf(), node);
  5646. }
  5647. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  5648. {
  5649. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  5650. // Parameters that are sent by reference should be assigned
  5651. // to the evaluated expression if it is an lvalue
  5652. // Evaluate the arguments from last to first
  5653. int n = (int)descr->parameterTypes.GetLength() - 1;
  5654. for( ; n >= 0; n-- )
  5655. {
  5656. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  5657. (descr->parameterTypes[n].IsObject() && deferAll) )
  5658. {
  5659. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  5660. // For &inout, only store the argument if it is for a temporary variable
  5661. if( engine->ep.allowUnsafeReferences ||
  5662. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  5663. {
  5664. // Store the argument for later processing
  5665. asSDeferredParam outParam;
  5666. outParam.argNode = args[n]->exprNode;
  5667. outParam.argType = args[n]->type;
  5668. outParam.argInOutFlags = descr->inOutFlags[n];
  5669. outParam.origExpr = args[n]->origExpr;
  5670. ctx->deferredParams.PushLast(outParam);
  5671. }
  5672. }
  5673. else
  5674. {
  5675. // Release the temporary variable now
  5676. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  5677. }
  5678. // Move the argument's deferred expressions over to the final expression
  5679. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  5680. {
  5681. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  5682. args[n]->deferredParams[m].origExpr = 0;
  5683. }
  5684. args[n]->deferredParams.SetLength(0);
  5685. }
  5686. }
  5687. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  5688. {
  5689. if( isProcessingDeferredParams ) return;
  5690. isProcessingDeferredParams = true;
  5691. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  5692. {
  5693. asSDeferredParam outParam = ctx->deferredParams[n];
  5694. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  5695. {
  5696. // Just release the variable
  5697. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5698. }
  5699. else if( outParam.argInOutFlags == asTM_OUTREF )
  5700. {
  5701. asSExprContext *expr = outParam.origExpr;
  5702. outParam.origExpr = 0;
  5703. if( outParam.argType.dataType.IsObjectHandle() )
  5704. {
  5705. // Implicitly convert the value to a handle
  5706. if( expr->type.dataType.IsObjectHandle() )
  5707. expr->type.isExplicitHandle = true;
  5708. }
  5709. // Verify that the expression result in a lvalue, or a property accessor
  5710. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  5711. {
  5712. asSExprContext rctx(engine);
  5713. rctx.type = outParam.argType;
  5714. if( rctx.type.dataType.IsPrimitive() )
  5715. rctx.type.dataType.MakeReference(false);
  5716. else
  5717. {
  5718. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  5719. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  5720. if( expr->type.isExplicitHandle )
  5721. rctx.type.isExplicitHandle = true;
  5722. }
  5723. asSExprContext o(engine);
  5724. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  5725. if( !o.type.dataType.IsPrimitive() ) o.bc.Pop(AS_PTR_SIZE);
  5726. MergeExprBytecode(ctx, &o);
  5727. }
  5728. else
  5729. {
  5730. // We must still evaluate the expression
  5731. MergeExprBytecode(ctx, expr);
  5732. if( !expr->type.isConstant )
  5733. ctx->bc.Pop(expr->type.dataType.GetSizeOnStackDWords());
  5734. // Give a warning
  5735. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  5736. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5737. }
  5738. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  5739. // Delete the original expression context
  5740. asDELETE(expr,asSExprContext);
  5741. }
  5742. else // &inout
  5743. {
  5744. if( outParam.argType.isTemporary )
  5745. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5746. else if( !outParam.argType.isVariable )
  5747. {
  5748. if( outParam.argType.dataType.IsObject() &&
  5749. outParam.argType.dataType.GetBehaviour()->addref &&
  5750. outParam.argType.dataType.GetBehaviour()->release )
  5751. {
  5752. // Release the object handle that was taken to guarantee the reference
  5753. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5754. }
  5755. }
  5756. }
  5757. }
  5758. ctx->deferredParams.SetLength(0);
  5759. isProcessingDeferredParams = false;
  5760. }
  5761. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  5762. {
  5763. // The first node is a datatype node
  5764. asCString name;
  5765. asCTypeInfo tempObj;
  5766. bool onHeap = true;
  5767. asCArray<int> funcs;
  5768. // It is possible that the name is really a constructor
  5769. asCDataType dt;
  5770. dt = builder->CreateDataTypeFromNode(node->firstChild, script);
  5771. if( dt.IsPrimitive() )
  5772. {
  5773. // This is a cast to a primitive type
  5774. CompileConversion(node, ctx);
  5775. return;
  5776. }
  5777. if( globalExpression )
  5778. {
  5779. Error(TXT_FUNCTION_IN_GLOBAL_EXPR, node);
  5780. // Output dummy code
  5781. ctx->type.SetDummy();
  5782. return;
  5783. }
  5784. // Compile the arguments
  5785. asCArray<asSExprContext *> args;
  5786. asCArray<asCTypeInfo> temporaryVariables;
  5787. if( CompileArgumentList(node->lastChild, args) >= 0 )
  5788. {
  5789. // Check for a value cast behaviour
  5790. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  5791. {
  5792. asSExprContext conv(engine);
  5793. conv.type = args[0]->type;
  5794. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  5795. if( conv.type.dataType.IsEqualExceptRef(dt) )
  5796. {
  5797. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  5798. ctx->bc.AddCode(&args[0]->bc);
  5799. ctx->type = args[0]->type;
  5800. asDELETE(args[0],asSExprContext);
  5801. return;
  5802. }
  5803. }
  5804. // Check for possible constructor/factory
  5805. name = dt.Format();
  5806. asSTypeBehaviour *beh = dt.GetBehaviour();
  5807. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  5808. {
  5809. funcs = beh->constructors;
  5810. // Value types and script types are allocated through the constructor
  5811. tempObj.dataType = dt;
  5812. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  5813. tempObj.dataType.MakeReference(true);
  5814. tempObj.isTemporary = true;
  5815. tempObj.isVariable = true;
  5816. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5817. // Push the address of the object on the stack
  5818. if( onHeap )
  5819. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5820. }
  5821. else
  5822. {
  5823. funcs = beh->factories;
  5824. }
  5825. // Special case: Allow calling func(void) with a void expression.
  5826. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  5827. {
  5828. // Evaluate the expression before the function call
  5829. MergeExprBytecode(ctx, args[0]);
  5830. asDELETE(args[0],asSExprContext);
  5831. args.SetLength(0);
  5832. }
  5833. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  5834. // If none has been registered, just allocate the variable and push it on the stack.
  5835. if( args.GetLength() == 0 )
  5836. {
  5837. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  5838. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  5839. {
  5840. // Call the default constructor
  5841. ctx->type = tempObj;
  5842. if( onHeap )
  5843. {
  5844. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  5845. ctx->bc.RemoveLastInstr();
  5846. }
  5847. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  5848. // Push the reference on the stack
  5849. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5850. return;
  5851. }
  5852. }
  5853. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  5854. if( funcs.GetLength() != 1 )
  5855. {
  5856. // The error was reported by MatchFunctions()
  5857. // Dummy value
  5858. ctx->type.SetDummy();
  5859. }
  5860. else
  5861. {
  5862. asCByteCode objBC(engine);
  5863. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  5864. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  5865. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  5866. {
  5867. // If the object is allocated on the stack, then call the constructor as a normal function
  5868. if( onHeap )
  5869. {
  5870. int offset = 0;
  5871. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5872. for( asUINT n = 0; n < args.GetLength(); n++ )
  5873. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  5874. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5875. }
  5876. else
  5877. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5878. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  5879. // The constructor doesn't return anything,
  5880. // so we have to manually inform the type of
  5881. // the return value
  5882. ctx->type = tempObj;
  5883. if( !onHeap )
  5884. ctx->type.dataType.MakeReference(false);
  5885. // Push the address of the object on the stack again
  5886. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5887. }
  5888. else
  5889. {
  5890. // Call the factory to create the reference type
  5891. PerformFunctionCall(funcs[0], ctx, false, &args);
  5892. }
  5893. }
  5894. }
  5895. else
  5896. {
  5897. // Failed to compile the argument list, set the result to the dummy type
  5898. ctx->type.SetDummy();
  5899. }
  5900. // Cleanup
  5901. for( asUINT n = 0; n < args.GetLength(); n++ )
  5902. if( args[n] )
  5903. {
  5904. asDELETE(args[n],asSExprContext);
  5905. }
  5906. }
  5907. void asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  5908. {
  5909. asCString name;
  5910. asCTypeInfo tempObj;
  5911. asCArray<int> funcs;
  5912. int r = -1;
  5913. asCScriptNode *nm = node->lastChild->prev;
  5914. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  5915. // TODO: funcdef: First check for a local variable of a function type
  5916. // Must not allow function names, nor global variables to be returned in this instance
  5917. asSExprContext funcPtr(engine);
  5918. if( objectType == 0 )
  5919. r = CompileVariableAccess(name, scope, &funcPtr, node, true, true, false);
  5920. if( r < 0 )
  5921. {
  5922. if( objectType )
  5923. {
  5924. // If we're compiling a constructor and the name of the function is super then
  5925. // the constructor of the base class is being called.
  5926. // super cannot be prefixed with a scope operator
  5927. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  5928. {
  5929. // If the class is not derived from anyone else, calling super should give an error
  5930. if( objectType->derivedFrom )
  5931. funcs = objectType->derivedFrom->beh.constructors;
  5932. }
  5933. else
  5934. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType, funcs, objIsConst, scope);
  5935. // It is still possible that there is a class member of a function type
  5936. if( funcs.GetLength() == 0 )
  5937. CompileVariableAccess(name, scope, &funcPtr, node, true, true, objectType);
  5938. }
  5939. else
  5940. {
  5941. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  5942. // TODO: funcdef: It is still possible that there is a global variable of a function type
  5943. }
  5944. }
  5945. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  5946. {
  5947. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  5948. }
  5949. if( globalExpression )
  5950. {
  5951. Error(TXT_FUNCTION_IN_GLOBAL_EXPR, node);
  5952. // Output dummy code
  5953. ctx->type.SetDummy();
  5954. return;
  5955. }
  5956. // Compile the arguments
  5957. asCArray<asSExprContext *> args;
  5958. asCArray<asCTypeInfo> temporaryVariables;
  5959. if( CompileArgumentList(node->lastChild, args) >= 0 )
  5960. {
  5961. // Special case: Allow calling func(void) with a void expression.
  5962. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  5963. {
  5964. // Evaluate the expression before the function call
  5965. MergeExprBytecode(ctx, args[0]);
  5966. asDELETE(args[0],asSExprContext);
  5967. args.SetLength(0);
  5968. }
  5969. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  5970. if( funcs.GetLength() != 1 )
  5971. {
  5972. // The error was reported by MatchFunctions()
  5973. // Dummy value
  5974. ctx->type.SetDummy();
  5975. }
  5976. else
  5977. {
  5978. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  5979. // is it enough to make sure it is in a local variable?
  5980. // For function pointer we must guarantee that the function is safe, i.e.
  5981. // by first storing the function pointer in a local variable (if it isn't already in one)
  5982. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  5983. {
  5984. if( objectType )
  5985. {
  5986. Dereference(ctx, true); // Dereference the object pointer to access the member
  5987. // The actual function should be called as if a global function
  5988. objectType = 0;
  5989. }
  5990. Dereference(&funcPtr, true);
  5991. ConvertToVariable(&funcPtr);
  5992. ctx->bc.AddCode(&funcPtr.bc);
  5993. if( !funcPtr.type.isTemporary )
  5994. ctx->bc.Pop(AS_PTR_SIZE);
  5995. }
  5996. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  5997. // If the function pointer was copied to a local variable for the call, then
  5998. // release it again (temporary local variable)
  5999. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6000. {
  6001. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  6002. }
  6003. }
  6004. }
  6005. else
  6006. {
  6007. // Failed to compile the argument list, set the dummy type and continue compilation
  6008. ctx->type.SetDummy();
  6009. }
  6010. // Cleanup
  6011. for( asUINT n = 0; n < args.GetLength(); n++ )
  6012. if( args[n] )
  6013. {
  6014. asDELETE(args[n],asSExprContext);
  6015. }
  6016. }
  6017. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  6018. {
  6019. int op = node->tokenType;
  6020. IsVariableInitialized(&ctx->type, node);
  6021. if( op == ttHandle )
  6022. {
  6023. // Verify that the type allow its handle to be taken
  6024. if( ctx->type.isExplicitHandle || !ctx->type.dataType.IsObject() || !ctx->type.dataType.GetObjectType()->beh.addref || !ctx->type.dataType.GetObjectType()->beh.release )
  6025. {
  6026. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  6027. return -1;
  6028. }
  6029. // Objects that are not local variables are not references
  6030. if( !ctx->type.dataType.IsReference() && !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) )
  6031. {
  6032. Error(TXT_NOT_VALID_REFERENCE, node);
  6033. return -1;
  6034. }
  6035. // If this is really an object then the handle created is a const handle
  6036. bool makeConst = !ctx->type.dataType.IsObjectHandle();
  6037. // Mark the type as an object handle
  6038. ctx->type.dataType.MakeHandle(true);
  6039. ctx->type.isExplicitHandle = true;
  6040. if( makeConst )
  6041. ctx->type.dataType.MakeReadOnly(true);
  6042. }
  6043. else if( (op == ttMinus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6044. {
  6045. // Look for the appropriate method
  6046. const char *opName = 0;
  6047. switch( op )
  6048. {
  6049. case ttMinus: opName = "opNeg"; break;
  6050. case ttBitNot: opName = "opCom"; break;
  6051. case ttInc: opName = "opPreInc"; break;
  6052. case ttDec: opName = "opPreDec"; break;
  6053. }
  6054. if( opName )
  6055. {
  6056. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6057. ProcessPropertyGetAccessor(ctx, node);
  6058. // Is it a const value?
  6059. bool isConst = false;
  6060. if( ctx->type.dataType.IsObjectHandle() )
  6061. isConst = ctx->type.dataType.IsHandleToConst();
  6062. else
  6063. isConst = ctx->type.dataType.IsReadOnly();
  6064. // 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
  6065. // Find the correct method
  6066. asCArray<int> funcs;
  6067. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6068. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6069. {
  6070. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6071. if( func->name == opName &&
  6072. func->parameterTypes.GetLength() == 0 &&
  6073. (!isConst || func->isReadOnly) )
  6074. {
  6075. funcs.PushLast(func->id);
  6076. }
  6077. }
  6078. // Did we find the method?
  6079. if( funcs.GetLength() == 1 )
  6080. {
  6081. asCTypeInfo objType = ctx->type;
  6082. asCArray<asSExprContext *> args;
  6083. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6084. ReleaseTemporaryVariable(objType, &ctx->bc);
  6085. return 0;
  6086. }
  6087. else if( funcs.GetLength() == 0 )
  6088. {
  6089. asCString str;
  6090. str = asCString(opName) + "()";
  6091. if( isConst )
  6092. str += " const";
  6093. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6094. Error(str.AddressOf(), node);
  6095. ctx->type.SetDummy();
  6096. return -1;
  6097. }
  6098. else if( funcs.GetLength() > 1 )
  6099. {
  6100. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6101. PrintMatchingFuncs(funcs, node);
  6102. ctx->type.SetDummy();
  6103. return -1;
  6104. }
  6105. }
  6106. }
  6107. else if( op == ttPlus || op == ttMinus )
  6108. {
  6109. ProcessPropertyGetAccessor(ctx, node);
  6110. asCDataType to = ctx->type.dataType;
  6111. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  6112. if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
  6113. {
  6114. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6115. to = asCDataType::CreatePrimitive(ttInt8, false);
  6116. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6117. to = asCDataType::CreatePrimitive(ttInt16, false);
  6118. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6119. to = asCDataType::CreatePrimitive(ttInt, false);
  6120. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6121. to = asCDataType::CreatePrimitive(ttInt64, false);
  6122. else
  6123. {
  6124. Error(TXT_INVALID_TYPE, node);
  6125. return -1;
  6126. }
  6127. }
  6128. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6129. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6130. if( !ctx->type.isConstant )
  6131. {
  6132. ConvertToTempVariable(ctx);
  6133. if( op == ttMinus )
  6134. {
  6135. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6136. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  6137. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6138. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  6139. else if( ctx->type.dataType.IsFloatType() )
  6140. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  6141. else if( ctx->type.dataType.IsDoubleType() )
  6142. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  6143. else
  6144. {
  6145. Error(TXT_ILLEGAL_OPERATION, node);
  6146. return -1;
  6147. }
  6148. return 0;
  6149. }
  6150. }
  6151. else
  6152. {
  6153. if( op == ttMinus )
  6154. {
  6155. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6156. ctx->type.intValue = -ctx->type.intValue;
  6157. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6158. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  6159. else if( ctx->type.dataType.IsFloatType() )
  6160. ctx->type.floatValue = -ctx->type.floatValue;
  6161. else if( ctx->type.dataType.IsDoubleType() )
  6162. ctx->type.doubleValue = -ctx->type.doubleValue;
  6163. else
  6164. {
  6165. Error(TXT_ILLEGAL_OPERATION, node);
  6166. return -1;
  6167. }
  6168. return 0;
  6169. }
  6170. }
  6171. if( op == ttPlus )
  6172. {
  6173. if( !ctx->type.dataType.IsIntegerType() &&
  6174. !ctx->type.dataType.IsFloatType() &&
  6175. !ctx->type.dataType.IsDoubleType() )
  6176. {
  6177. Error(TXT_ILLEGAL_OPERATION, node);
  6178. return -1;
  6179. }
  6180. }
  6181. }
  6182. else if( op == ttNot )
  6183. {
  6184. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6185. {
  6186. if( ctx->type.isConstant )
  6187. {
  6188. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  6189. return 0;
  6190. }
  6191. ProcessPropertyGetAccessor(ctx, node);
  6192. ConvertToTempVariable(ctx);
  6193. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  6194. }
  6195. else
  6196. {
  6197. Error(TXT_ILLEGAL_OPERATION, node);
  6198. return -1;
  6199. }
  6200. }
  6201. else if( op == ttBitNot )
  6202. {
  6203. ProcessPropertyGetAccessor(ctx, node);
  6204. asCDataType to = ctx->type.dataType;
  6205. if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
  6206. {
  6207. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6208. to = asCDataType::CreatePrimitive(ttUInt8, false);
  6209. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6210. to = asCDataType::CreatePrimitive(ttUInt16, false);
  6211. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6212. to = asCDataType::CreatePrimitive(ttUInt, false);
  6213. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6214. to = asCDataType::CreatePrimitive(ttUInt64, false);
  6215. else
  6216. {
  6217. Error(TXT_INVALID_TYPE, node);
  6218. return -1;
  6219. }
  6220. }
  6221. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6222. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6223. if( ctx->type.dataType.IsUnsignedType() )
  6224. {
  6225. if( ctx->type.isConstant )
  6226. {
  6227. ctx->type.qwordValue = ~ctx->type.qwordValue;
  6228. return 0;
  6229. }
  6230. ConvertToTempVariable(ctx);
  6231. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6232. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  6233. else
  6234. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  6235. }
  6236. else
  6237. {
  6238. Error(TXT_ILLEGAL_OPERATION, node);
  6239. return -1;
  6240. }
  6241. }
  6242. else if( op == ttInc || op == ttDec )
  6243. {
  6244. // Need a reference to the primitive that will be updated
  6245. // The result of this expression is the same reference as before
  6246. if( globalExpression )
  6247. {
  6248. Error(TXT_INC_OP_IN_GLOBAL_EXPR, node);
  6249. return -1;
  6250. }
  6251. // Make sure the reference isn't a temporary variable
  6252. if( ctx->type.isTemporary )
  6253. {
  6254. Error(TXT_REF_IS_TEMP, node);
  6255. return -1;
  6256. }
  6257. if( ctx->type.dataType.IsReadOnly() )
  6258. {
  6259. Error(TXT_REF_IS_READ_ONLY, node);
  6260. return -1;
  6261. }
  6262. if( ctx->property_get || ctx->property_set )
  6263. {
  6264. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6265. return -1;
  6266. }
  6267. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6268. ConvertToReference(ctx);
  6269. else if( !ctx->type.dataType.IsReference() )
  6270. {
  6271. Error(TXT_NOT_VALID_REFERENCE, node);
  6272. return -1;
  6273. }
  6274. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6275. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6276. {
  6277. if( op == ttInc )
  6278. ctx->bc.Instr(asBC_INCi64);
  6279. else
  6280. ctx->bc.Instr(asBC_DECi64);
  6281. }
  6282. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  6283. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  6284. {
  6285. if( op == ttInc )
  6286. ctx->bc.Instr(asBC_INCi);
  6287. else
  6288. ctx->bc.Instr(asBC_DECi);
  6289. }
  6290. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6291. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6292. {
  6293. if( op == ttInc )
  6294. ctx->bc.Instr(asBC_INCi16);
  6295. else
  6296. ctx->bc.Instr(asBC_DECi16);
  6297. }
  6298. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6299. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6300. {
  6301. if( op == ttInc )
  6302. ctx->bc.Instr(asBC_INCi8);
  6303. else
  6304. ctx->bc.Instr(asBC_DECi8);
  6305. }
  6306. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  6307. {
  6308. if( op == ttInc )
  6309. ctx->bc.Instr(asBC_INCf);
  6310. else
  6311. ctx->bc.Instr(asBC_DECf);
  6312. }
  6313. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  6314. {
  6315. if( op == ttInc )
  6316. ctx->bc.Instr(asBC_INCd);
  6317. else
  6318. ctx->bc.Instr(asBC_DECd);
  6319. }
  6320. else
  6321. {
  6322. Error(TXT_ILLEGAL_OPERATION, node);
  6323. return -1;
  6324. }
  6325. }
  6326. else
  6327. {
  6328. // Unknown operator
  6329. asASSERT(false);
  6330. return -1;
  6331. }
  6332. return 0;
  6333. }
  6334. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  6335. {
  6336. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6337. {
  6338. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  6339. ctx->type.dataType.MakeReference(true);
  6340. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  6341. }
  6342. }
  6343. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node)
  6344. {
  6345. return FindPropertyAccessor(name, ctx, 0, node);
  6346. }
  6347. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  6348. {
  6349. if( engine->ep.propertyAccessorMode == 0 )
  6350. {
  6351. // Property accessors have been disabled by the application
  6352. return 0;
  6353. }
  6354. int getId = 0, setId = 0;
  6355. asCString getName = "get_" + name;
  6356. asCString setName = "set_" + name;
  6357. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  6358. if( ctx->type.dataType.IsObject() )
  6359. {
  6360. // Check if the object has any methods with the property name prefixed by get_ or set_
  6361. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6362. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6363. {
  6364. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  6365. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6366. if( f->name == getName && f->parameterTypes.GetLength() == (arg?1:0) )
  6367. {
  6368. if( getId == 0 )
  6369. getId = ot->methods[n];
  6370. else
  6371. {
  6372. if( multipleGetFuncs.GetLength() == 0 )
  6373. multipleGetFuncs.PushLast(getId);
  6374. multipleGetFuncs.PushLast(ot->methods[n]);
  6375. }
  6376. }
  6377. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6378. if( f->name == setName && f->parameterTypes.GetLength() == (arg?2:1) )
  6379. {
  6380. if( setId == 0 )
  6381. setId = ot->methods[n];
  6382. else
  6383. {
  6384. if( multipleSetFuncs.GetLength() == 0 )
  6385. multipleSetFuncs.PushLast(setId);
  6386. multipleSetFuncs.PushLast(ot->methods[n]);
  6387. }
  6388. }
  6389. }
  6390. }
  6391. else
  6392. {
  6393. // Look for appropriate global functions.
  6394. asCArray<int> funcs;
  6395. asUINT n;
  6396. builder->GetFunctionDescriptions(getName.AddressOf(), funcs);
  6397. for( n = 0; n < funcs.GetLength(); n++ )
  6398. {
  6399. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6400. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6401. if( f->parameterTypes.GetLength() == (arg?1:0) )
  6402. {
  6403. if( getId == 0 )
  6404. getId = funcs[n];
  6405. else
  6406. {
  6407. if( multipleGetFuncs.GetLength() == 0 )
  6408. multipleGetFuncs.PushLast(getId);
  6409. multipleGetFuncs.PushLast(funcs[n]);
  6410. }
  6411. }
  6412. }
  6413. funcs.SetLength(0);
  6414. builder->GetFunctionDescriptions(setName.AddressOf(), funcs);
  6415. for( n = 0; n < funcs.GetLength(); n++ )
  6416. {
  6417. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6418. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6419. if( f->parameterTypes.GetLength() == (arg?2:1) )
  6420. {
  6421. if( setId == 0 )
  6422. setId = funcs[n];
  6423. else
  6424. {
  6425. if( multipleSetFuncs.GetLength() == 0 )
  6426. multipleSetFuncs.PushLast(getId);
  6427. multipleSetFuncs.PushLast(funcs[n]);
  6428. }
  6429. }
  6430. }
  6431. }
  6432. // Check for multiple matches
  6433. if( multipleGetFuncs.GetLength() > 0 )
  6434. {
  6435. asCString str;
  6436. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  6437. Error(str.AddressOf(), node);
  6438. PrintMatchingFuncs(multipleGetFuncs, node);
  6439. return -1;
  6440. }
  6441. if( multipleSetFuncs.GetLength() > 0 )
  6442. {
  6443. asCString str;
  6444. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  6445. Error(str.AddressOf(), node);
  6446. PrintMatchingFuncs(multipleSetFuncs, node);
  6447. return -1;
  6448. }
  6449. // Check for type compatibility between get and set accessor
  6450. if( getId && setId )
  6451. {
  6452. asCScriptFunction *getFunc = engine->scriptFunctions[getId];
  6453. asCScriptFunction *setFunc = engine->scriptFunctions[setId];
  6454. // It is permitted for a getter to return a handle and the setter to take a reference
  6455. int idx = (arg?1:0);
  6456. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  6457. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  6458. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  6459. {
  6460. asCString str;
  6461. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  6462. Error(str.AddressOf(), node);
  6463. asCArray<int> funcs;
  6464. funcs.PushLast(getId);
  6465. funcs.PushLast(setId);
  6466. PrintMatchingFuncs(funcs, node);
  6467. return -1;
  6468. }
  6469. }
  6470. // Check if we are within one of the accessors
  6471. int realGetId = getId;
  6472. int realSetId = setId;
  6473. if( outFunc->objectType )
  6474. {
  6475. // The property accessors would be virtual functions, so we need to find the real implementation
  6476. asCScriptFunction *getFunc = getId ? engine->scriptFunctions[getId] : 0;
  6477. if( getFunc &&
  6478. getFunc->funcType == asFUNC_VIRTUAL &&
  6479. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  6480. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  6481. asCScriptFunction *setFunc = setId ? engine->scriptFunctions[setId] : 0;
  6482. if( setFunc &&
  6483. setFunc->funcType == asFUNC_VIRTUAL &&
  6484. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  6485. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  6486. }
  6487. if( (realGetId && realGetId == outFunc->id) ||
  6488. (realSetId && realSetId == outFunc->id) )
  6489. {
  6490. // Avoid recursive call, by not treating this as a property accessor call.
  6491. // This will also allow having the real property with the same name as the accessors.
  6492. getId = 0;
  6493. setId = 0;
  6494. }
  6495. // Check if the application has disabled script written property accessors
  6496. if( engine->ep.propertyAccessorMode == 1 )
  6497. {
  6498. if( getId && engine->scriptFunctions[getId]->funcType != asFUNC_SYSTEM )
  6499. getId = 0;
  6500. if( setId && engine->scriptFunctions[setId]->funcType != asFUNC_SYSTEM )
  6501. setId = 0;
  6502. }
  6503. if( getId || setId )
  6504. {
  6505. // Property accessors were found, but we don't know which is to be used yet, so
  6506. // we just prepare the bytecode for the method call, and then store the function ids
  6507. // so that the right one can be used when we get there.
  6508. ctx->property_get = getId;
  6509. ctx->property_set = setId;
  6510. if( ctx->type.dataType.IsObject() )
  6511. {
  6512. // If the object is read-only then we need to remember that
  6513. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  6514. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  6515. ctx->property_const = true;
  6516. else
  6517. ctx->property_const = false;
  6518. // If the object is a handle then we need to remember that
  6519. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  6520. ctx->property_ref = ctx->type.dataType.IsReference();
  6521. }
  6522. // The setter's parameter type is used as the property type,
  6523. // unless only the getter is available
  6524. asCDataType dt;
  6525. if( setId )
  6526. dt = engine->scriptFunctions[setId]->parameterTypes[(arg?1:0)];
  6527. else
  6528. dt = engine->scriptFunctions[getId]->returnType;
  6529. // Just change the type, the context must still maintain information
  6530. // about previous variable offset and the indicator of temporary variable.
  6531. int offset = ctx->type.stackOffset;
  6532. bool isTemp = ctx->type.isTemporary;
  6533. ctx->type.Set(dt);
  6534. ctx->type.stackOffset = offset;
  6535. ctx->type.isTemporary = isTemp;
  6536. ctx->exprNode = node;
  6537. // Store the argument for later use
  6538. if( arg )
  6539. {
  6540. ctx->property_arg = asNEW(asSExprContext)(engine);
  6541. MergeExprBytecodeAndType(ctx->property_arg, arg);
  6542. }
  6543. return 1;
  6544. }
  6545. // No accessor was found
  6546. return 0;
  6547. }
  6548. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  6549. {
  6550. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  6551. if( !ctx->property_set )
  6552. {
  6553. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  6554. return -1;
  6555. }
  6556. asCTypeInfo objType = ctx->type;
  6557. asCScriptFunction *func = engine->scriptFunctions[ctx->property_set];
  6558. // Make sure the arg match the property
  6559. asCArray<int> funcs;
  6560. funcs.PushLast(ctx->property_set);
  6561. asCArray<asSExprContext *> args;
  6562. if( ctx->property_arg )
  6563. args.PushLast(ctx->property_arg);
  6564. args.PushLast(arg);
  6565. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  6566. if( funcs.GetLength() == 0 )
  6567. {
  6568. // MatchFunctions already reported the error
  6569. if( ctx->property_arg )
  6570. {
  6571. asDELETE(ctx->property_arg, asSExprContext);
  6572. ctx->property_arg = 0;
  6573. }
  6574. return -1;
  6575. }
  6576. if( func->objectType )
  6577. {
  6578. // Setup the context with the original type so the method call gets built correctly
  6579. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6580. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6581. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6582. // Don't allow the call if the object is read-only and the property accessor is not const
  6583. if( ctx->property_const && !func->isReadOnly )
  6584. {
  6585. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  6586. asCArray<int> funcs;
  6587. funcs.PushLast(ctx->property_set);
  6588. PrintMatchingFuncs(funcs, node);
  6589. }
  6590. }
  6591. // Call the accessor
  6592. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  6593. if( func->objectType )
  6594. {
  6595. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  6596. if( objType.isTemporary &&
  6597. ctx->type.dataType.IsReference() &&
  6598. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6599. {
  6600. // Remember the original object's variable, so that it can be released
  6601. // later on when the reference to its member goes out of scope
  6602. ctx->type.isTemporary = true;
  6603. ctx->type.stackOffset = objType.stackOffset;
  6604. }
  6605. else
  6606. {
  6607. // As the method didn't return a reference to a member
  6608. // we can safely release the original object now
  6609. ReleaseTemporaryVariable(objType, &ctx->bc);
  6610. }
  6611. }
  6612. ctx->property_get = 0;
  6613. ctx->property_set = 0;
  6614. if( ctx->property_arg )
  6615. {
  6616. asDELETE(ctx->property_arg, asSExprContext);
  6617. ctx->property_arg = 0;
  6618. }
  6619. return 0;
  6620. }
  6621. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  6622. {
  6623. // If no property accessor has been prepared then don't do anything
  6624. if( !ctx->property_get && !ctx->property_set )
  6625. return;
  6626. if( !ctx->property_get )
  6627. {
  6628. // Raise error on missing accessor
  6629. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  6630. ctx->type.SetDummy();
  6631. return;
  6632. }
  6633. asCTypeInfo objType = ctx->type;
  6634. asCScriptFunction *func = engine->scriptFunctions[ctx->property_get];
  6635. // Make sure the arg match the property
  6636. asCArray<int> funcs;
  6637. funcs.PushLast(ctx->property_get);
  6638. asCArray<asSExprContext *> args;
  6639. if( ctx->property_arg )
  6640. args.PushLast(ctx->property_arg);
  6641. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  6642. if( funcs.GetLength() == 0 )
  6643. {
  6644. // MatchFunctions already reported the error
  6645. if( ctx->property_arg )
  6646. {
  6647. asDELETE(ctx->property_arg, asSExprContext);
  6648. ctx->property_arg = 0;
  6649. }
  6650. ctx->type.SetDummy();
  6651. return;
  6652. }
  6653. if( func->objectType )
  6654. {
  6655. // Setup the context with the original type so the method call gets built correctly
  6656. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6657. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6658. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6659. // Don't allow the call if the object is read-only and the property accessor is not const
  6660. if( ctx->property_const && !func->isReadOnly )
  6661. {
  6662. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  6663. asCArray<int> funcs;
  6664. funcs.PushLast(ctx->property_get);
  6665. PrintMatchingFuncs(funcs, node);
  6666. }
  6667. }
  6668. // Call the accessor
  6669. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  6670. if( func->objectType )
  6671. {
  6672. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  6673. if( objType.isTemporary &&
  6674. ctx->type.dataType.IsReference() &&
  6675. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6676. {
  6677. // Remember the original object's variable, so that it can be released
  6678. // later on when the reference to its member goes out of scope
  6679. ctx->type.isTemporary = true;
  6680. ctx->type.stackOffset = objType.stackOffset;
  6681. }
  6682. else
  6683. {
  6684. // As the method didn't return a reference to a member
  6685. // we can safely release the original object now
  6686. ReleaseTemporaryVariable(objType, &ctx->bc);
  6687. }
  6688. }
  6689. ctx->property_get = 0;
  6690. ctx->property_set = 0;
  6691. if( ctx->property_arg )
  6692. {
  6693. asDELETE(ctx->property_arg, asSExprContext);
  6694. ctx->property_arg = 0;
  6695. }
  6696. }
  6697. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  6698. {
  6699. int op = node->tokenType;
  6700. // Check if the variable is initialized (if it indeed is a variable)
  6701. IsVariableInitialized(&ctx->type, node);
  6702. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6703. {
  6704. const char *opName = 0;
  6705. switch( op )
  6706. {
  6707. case ttInc: opName = "opPostInc"; break;
  6708. case ttDec: opName = "opPostDec"; break;
  6709. }
  6710. if( opName )
  6711. {
  6712. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6713. ProcessPropertyGetAccessor(ctx, node);
  6714. // Is it a const value?
  6715. bool isConst = false;
  6716. if( ctx->type.dataType.IsObjectHandle() )
  6717. isConst = ctx->type.dataType.IsHandleToConst();
  6718. else
  6719. isConst = ctx->type.dataType.IsReadOnly();
  6720. // 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
  6721. // Find the correct method
  6722. asCArray<int> funcs;
  6723. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6724. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6725. {
  6726. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6727. if( func->name == opName &&
  6728. func->parameterTypes.GetLength() == 0 &&
  6729. (!isConst || func->isReadOnly) )
  6730. {
  6731. funcs.PushLast(func->id);
  6732. }
  6733. }
  6734. // Did we find the method?
  6735. if( funcs.GetLength() == 1 )
  6736. {
  6737. asCTypeInfo objType = ctx->type;
  6738. asCArray<asSExprContext *> args;
  6739. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6740. ReleaseTemporaryVariable(objType, &ctx->bc);
  6741. return 0;
  6742. }
  6743. else if( funcs.GetLength() == 0 )
  6744. {
  6745. asCString str;
  6746. str = asCString(opName) + "()";
  6747. if( isConst )
  6748. str += " const";
  6749. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6750. Error(str.AddressOf(), node);
  6751. ctx->type.SetDummy();
  6752. return -1;
  6753. }
  6754. else if( funcs.GetLength() > 1 )
  6755. {
  6756. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6757. PrintMatchingFuncs(funcs, node);
  6758. ctx->type.SetDummy();
  6759. return -1;
  6760. }
  6761. }
  6762. }
  6763. else if( op == ttInc || op == ttDec )
  6764. {
  6765. if( globalExpression )
  6766. {
  6767. Error(TXT_INC_OP_IN_GLOBAL_EXPR, node);
  6768. return -1;
  6769. }
  6770. // Make sure the reference isn't a temporary variable
  6771. if( ctx->type.isTemporary )
  6772. {
  6773. Error(TXT_REF_IS_TEMP, node);
  6774. return -1;
  6775. }
  6776. if( ctx->type.dataType.IsReadOnly() )
  6777. {
  6778. Error(TXT_REF_IS_READ_ONLY, node);
  6779. return -1;
  6780. }
  6781. if( ctx->property_get || ctx->property_set )
  6782. {
  6783. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6784. return -1;
  6785. }
  6786. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6787. ConvertToReference(ctx);
  6788. else if( !ctx->type.dataType.IsReference() )
  6789. {
  6790. Error(TXT_NOT_VALID_REFERENCE, node);
  6791. return -1;
  6792. }
  6793. // Copy the value to a temp before changing it
  6794. ConvertToTempVariable(ctx);
  6795. // Increment the value pointed to by the reference still in the register
  6796. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  6797. if( ctx->type.dataType.IsDoubleType() )
  6798. {
  6799. iInc = asBC_INCd;
  6800. iDec = asBC_DECd;
  6801. }
  6802. else if( ctx->type.dataType.IsFloatType() )
  6803. {
  6804. iInc = asBC_INCf;
  6805. iDec = asBC_DECf;
  6806. }
  6807. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  6808. {
  6809. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6810. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6811. {
  6812. iInc = asBC_INCi16;
  6813. iDec = asBC_DECi16;
  6814. }
  6815. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6816. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6817. {
  6818. iInc = asBC_INCi8;
  6819. iDec = asBC_DECi8;
  6820. }
  6821. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6822. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6823. {
  6824. iInc = asBC_INCi64;
  6825. iDec = asBC_DECi64;
  6826. }
  6827. }
  6828. else
  6829. {
  6830. Error(TXT_ILLEGAL_OPERATION, node);
  6831. return -1;
  6832. }
  6833. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  6834. }
  6835. else if( op == ttDot )
  6836. {
  6837. if( node->firstChild->nodeType == snIdentifier )
  6838. {
  6839. ProcessPropertyGetAccessor(ctx, node);
  6840. // Get the property name
  6841. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  6842. // We need to look for get/set property accessors.
  6843. // If found, the context stores information on the get/set accessors
  6844. // until it is known which is to be used.
  6845. int r = 0;
  6846. if( node->next && node->next->tokenType == ttOpenBracket )
  6847. {
  6848. // The property accessor should take an index arg
  6849. asSExprContext dummyArg(engine);
  6850. r = FindPropertyAccessor(name, ctx, &dummyArg, node);
  6851. }
  6852. if( r == 0 )
  6853. r = FindPropertyAccessor(name, ctx, node);
  6854. if( r != 0 )
  6855. return r;
  6856. if( !ctx->type.dataType.IsPrimitive() )
  6857. Dereference(ctx, true);
  6858. if( ctx->type.dataType.IsObjectHandle() )
  6859. {
  6860. // Convert the handle to a normal object
  6861. asCDataType dt = ctx->type.dataType;
  6862. dt.MakeHandle(false);
  6863. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  6864. }
  6865. // Find the property offset and type
  6866. if( ctx->type.dataType.IsObject() )
  6867. {
  6868. bool isConst = ctx->type.dataType.IsReadOnly();
  6869. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  6870. if( prop )
  6871. {
  6872. // Is the property access allowed?
  6873. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  6874. {
  6875. asCString msg;
  6876. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  6877. Error(msg.AddressOf(), node);
  6878. }
  6879. // Put the offset on the stack
  6880. ctx->bc.InstrSHORT_DW(asBC_ADDSi, prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  6881. if( prop->type.IsReference() )
  6882. ctx->bc.Instr(asBC_RDSPTR);
  6883. // Reference to primitive must be stored in the temp register
  6884. if( prop->type.IsPrimitive() )
  6885. {
  6886. ctx->bc.Instr(asBC_PopRPtr);
  6887. }
  6888. // Set the new type (keeping info about temp variable)
  6889. ctx->type.dataType = prop->type;
  6890. ctx->type.dataType.MakeReference(true);
  6891. ctx->type.isVariable = false;
  6892. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  6893. {
  6894. // Objects that are members are not references
  6895. ctx->type.dataType.MakeReference(false);
  6896. }
  6897. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  6898. }
  6899. else
  6900. {
  6901. asCString str;
  6902. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  6903. Error(str.AddressOf(), node);
  6904. return -1;
  6905. }
  6906. }
  6907. else
  6908. {
  6909. asCString str;
  6910. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  6911. Error(str.AddressOf(), node);
  6912. return -1;
  6913. }
  6914. }
  6915. else
  6916. {
  6917. if( globalExpression )
  6918. {
  6919. Error(TXT_METHOD_IN_GLOBAL_EXPR, node);
  6920. return -1;
  6921. }
  6922. // Make sure it is an object we are accessing
  6923. if( !ctx->type.dataType.IsObject() )
  6924. {
  6925. asCString str;
  6926. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  6927. Error(str.AddressOf(), node);
  6928. return -1;
  6929. }
  6930. // Process the get property accessor
  6931. ProcessPropertyGetAccessor(ctx, node);
  6932. bool isConst = false;
  6933. if( ctx->type.dataType.IsObjectHandle() )
  6934. isConst = ctx->type.dataType.IsHandleToConst();
  6935. else
  6936. isConst = ctx->type.dataType.IsReadOnly();
  6937. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  6938. asCTypeInfo objType = ctx->type;
  6939. // Compile function call
  6940. CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  6941. // If the method returned a reference, then we can't release the original
  6942. // object yet, because the reference may be to a member of it
  6943. if( objType.isTemporary &&
  6944. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  6945. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6946. {
  6947. // Remember the original object's variable, so that it can be released
  6948. // later on when the reference to its member goes out of scope
  6949. ctx->type.isTemporary = true;
  6950. ctx->type.stackOffset = objType.stackOffset;
  6951. }
  6952. else
  6953. {
  6954. // As the method didn't return a reference to a member
  6955. // we can safely release the original object now
  6956. ReleaseTemporaryVariable(objType, &ctx->bc);
  6957. }
  6958. }
  6959. }
  6960. else if( op == ttOpenBracket )
  6961. {
  6962. // If the property access takes an index arg, then we should use that instead of processing it now
  6963. asCString propertyName;
  6964. if( (ctx->property_get && engine->scriptFunctions[ctx->property_get]->GetParamCount() == 1) ||
  6965. (ctx->property_set && engine->scriptFunctions[ctx->property_get]->GetParamCount() == 2) )
  6966. {
  6967. // Determine the name of the property accessor
  6968. asCScriptFunction *func = 0;
  6969. if( ctx->property_get )
  6970. func = engine->scriptFunctions[ctx->property_get];
  6971. else
  6972. func = engine->scriptFunctions[ctx->property_get];
  6973. propertyName = func->GetName();
  6974. propertyName = propertyName.SubString(4);
  6975. // Set the original type of the expression so we can re-evaluate the property accessor
  6976. if( func->objectType )
  6977. {
  6978. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6979. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6980. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6981. }
  6982. ctx->property_get = ctx->property_set = 0;
  6983. if( ctx->property_arg )
  6984. {
  6985. asDELETE(ctx->property_arg, asSExprContext);
  6986. ctx->property_arg = 0;
  6987. }
  6988. }
  6989. else
  6990. {
  6991. if( !ctx->type.dataType.IsObject() )
  6992. {
  6993. asCString str;
  6994. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  6995. Error(str.AddressOf(), node);
  6996. return -1;
  6997. }
  6998. ProcessPropertyGetAccessor(ctx, node);
  6999. }
  7000. Dereference(ctx, true);
  7001. #ifdef AS_DEPRECATED
  7002. // Since 2.20.0
  7003. bool isConst = ctx->type.dataType.IsReadOnly();
  7004. #endif
  7005. // Compile the expression
  7006. asSExprContext expr(engine);
  7007. CompileAssignment(node->firstChild, &expr);
  7008. // Check for the existence of the opIndex method
  7009. asSExprContext lctx(engine);
  7010. MergeExprBytecodeAndType(&lctx, ctx);
  7011. int r = 0;
  7012. if( propertyName == "" )
  7013. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  7014. if( r == 0 )
  7015. {
  7016. #ifndef AS_DEPRECATED
  7017. // Check for accessors methods for the opIndex
  7018. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node);
  7019. if( r == 0 )
  7020. {
  7021. asCString str;
  7022. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7023. Error(str.AddressOf(), node);
  7024. return -1;
  7025. }
  7026. else if( r < 0 )
  7027. return -1;
  7028. MergeExprBytecodeAndType(ctx, &lctx);
  7029. #else
  7030. // Deprecated since 2.20.0
  7031. MergeExprBytecodeAndType(ctx, &lctx);
  7032. if( ctx->type.dataType.IsObjectHandle() )
  7033. {
  7034. // Convert the handle to a normal object
  7035. asCDataType dt = ctx->type.dataType;
  7036. dt.MakeHandle(false);
  7037. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  7038. }
  7039. asCTypeInfo objType = ctx->type;
  7040. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  7041. if( beh == 0 )
  7042. {
  7043. asCString str;
  7044. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7045. Error(str.AddressOf(), node);
  7046. return -1;
  7047. }
  7048. else
  7049. {
  7050. // Now find a matching function for the object type and indexing type
  7051. asCArray<int> ops;
  7052. asUINT n;
  7053. if( isConst )
  7054. {
  7055. // Only list const behaviours
  7056. for( n = 0; n < beh->operators.GetLength(); n += 2 )
  7057. {
  7058. if( asBEHAVE_INDEX == beh->operators[n] && engine->scriptFunctions[beh->operators[n+1]]->isReadOnly )
  7059. ops.PushLast(beh->operators[n+1]);
  7060. }
  7061. }
  7062. else
  7063. {
  7064. // TODO: Prefer non-const over const
  7065. for( n = 0; n < beh->operators.GetLength(); n += 2 )
  7066. {
  7067. if( asBEHAVE_INDEX == beh->operators[n] )
  7068. ops.PushLast(beh->operators[n+1]);
  7069. }
  7070. }
  7071. asCArray<int> ops1;
  7072. MatchArgument(ops, ops1, &expr.type, 0);
  7073. if( !isConst )
  7074. FilterConst(ops1);
  7075. // Did we find a suitable function?
  7076. if( ops1.GetLength() == 1 )
  7077. {
  7078. asCScriptFunction *descr = engine->scriptFunctions[ops1[0]];
  7079. // Store the code for the object
  7080. asCByteCode objBC(engine);
  7081. objBC.AddCode(&ctx->bc);
  7082. // Add code for arguments
  7083. PrepareArgument(&descr->parameterTypes[0], &expr, node->firstChild, true, descr->inOutFlags[0]);
  7084. MergeExprBytecode(ctx, &expr);
  7085. if( descr->parameterTypes[0].IsReference() )
  7086. {
  7087. if( descr->parameterTypes[0].IsObject() && !descr->parameterTypes[0].IsObjectHandle() )
  7088. ctx->bc.InstrWORD(asBC_GETOBJREF, 0);
  7089. else
  7090. ctx->bc.InstrWORD(asBC_GETREF, 0);
  7091. }
  7092. else if( descr->parameterTypes[0].IsObject() )
  7093. {
  7094. ctx->bc.InstrWORD(asBC_GETOBJ, 0);
  7095. // The temporary variable must not be freed as it will no longer hold an object
  7096. DeallocateVariable(expr.type.stackOffset);
  7097. expr.type.isTemporary = false;
  7098. }
  7099. // Add the code for the object again
  7100. ctx->bc.AddCode(&objBC);
  7101. asCArray<asSExprContext*> args;
  7102. args.PushLast(&expr);
  7103. PerformFunctionCall(descr->id, ctx, false, &args);
  7104. }
  7105. else if( ops.GetLength() > 1 )
  7106. {
  7107. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7108. PrintMatchingFuncs(ops, node);
  7109. return -1;
  7110. }
  7111. else
  7112. {
  7113. asCString str;
  7114. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPE_s, expr.type.dataType.Format().AddressOf());
  7115. Error(str.AddressOf(), node);
  7116. return -1;
  7117. }
  7118. }
  7119. // If the method returned a reference, then we can't release the original
  7120. // object yet, because the reference may be to a member of it
  7121. if( objType.isTemporary &&
  7122. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7123. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  7124. {
  7125. // Remember the object's variable, so that it can be released
  7126. // later on when the reference to its member goes out of scope
  7127. ctx->type.isTemporary = true;
  7128. ctx->type.stackOffset = objType.stackOffset;
  7129. }
  7130. else
  7131. {
  7132. // As the index operator didn't return a reference to a
  7133. // member we can release the original object now
  7134. ReleaseTemporaryVariable(objType, &ctx->bc);
  7135. }
  7136. #endif
  7137. }
  7138. }
  7139. return 0;
  7140. }
  7141. int asCCompiler::GetPrecedence(asCScriptNode *op)
  7142. {
  7143. // x * y, x / y, x % y
  7144. // x + y, x - y
  7145. // x <= y, x < y, x >= y, x > y
  7146. // x = =y, x != y, x xor y, x is y, x !is y
  7147. // x and y
  7148. // x or y
  7149. // The following are not used in this function,
  7150. // but should have lower precedence than the above
  7151. // x ? y : z
  7152. // x = y
  7153. // The expression term have the highest precedence
  7154. if( op->nodeType == snExprTerm )
  7155. return 1;
  7156. // Evaluate operators by token
  7157. int tokenType = op->tokenType;
  7158. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  7159. return 0;
  7160. if( tokenType == ttPlus || tokenType == ttMinus )
  7161. return -1;
  7162. if( tokenType == ttBitShiftLeft ||
  7163. tokenType == ttBitShiftRight ||
  7164. tokenType == ttBitShiftRightArith )
  7165. return -2;
  7166. if( tokenType == ttAmp )
  7167. return -3;
  7168. if( tokenType == ttBitXor )
  7169. return -4;
  7170. if( tokenType == ttBitOr )
  7171. return -5;
  7172. if( tokenType == ttLessThanOrEqual ||
  7173. tokenType == ttLessThan ||
  7174. tokenType == ttGreaterThanOrEqual ||
  7175. tokenType == ttGreaterThan )
  7176. return -6;
  7177. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  7178. return -7;
  7179. if( tokenType == ttAnd )
  7180. return -8;
  7181. if( tokenType == ttOr )
  7182. return -9;
  7183. // Unknown operator
  7184. asASSERT(false);
  7185. return 0;
  7186. }
  7187. int asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<int> &matches, const asCTypeInfo *argType, int paramNum, bool allowObjectConstruct)
  7188. {
  7189. bool isExactMatch = false;
  7190. bool isMatchExceptConst = false;
  7191. bool isMatchWithBaseType = false;
  7192. bool isMatchExceptSign = false;
  7193. bool isMatchNotVarType = false;
  7194. asUINT n;
  7195. matches.SetLength(0);
  7196. for( n = 0; n < funcs.GetLength(); n++ )
  7197. {
  7198. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  7199. // Does the function have arguments enough?
  7200. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  7201. continue;
  7202. // Can we make the match by implicit conversion?
  7203. asSExprContext ti(engine);
  7204. ti.type = *argType;
  7205. if( argType->dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  7206. ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, 0, allowObjectConstruct);
  7207. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  7208. {
  7209. // Is it an exact match?
  7210. if( argType->dataType.IsEqualExceptRef(ti.type.dataType) )
  7211. {
  7212. if( !isExactMatch ) matches.SetLength(0);
  7213. isExactMatch = true;
  7214. matches.PushLast(funcs[n]);
  7215. continue;
  7216. }
  7217. if( !isExactMatch )
  7218. {
  7219. // Is it a match except const?
  7220. if( argType->dataType.IsEqualExceptRefAndConst(ti.type.dataType) )
  7221. {
  7222. if( !isMatchExceptConst ) matches.SetLength(0);
  7223. isMatchExceptConst = true;
  7224. matches.PushLast(funcs[n]);
  7225. continue;
  7226. }
  7227. if( !isMatchExceptConst )
  7228. {
  7229. // Is it a size promotion, e.g. int8 -> int?
  7230. if( argType->dataType.IsSamePrimitiveBaseType(ti.type.dataType) ||
  7231. (argType->dataType.IsEnumType() && ti.type.dataType.IsIntegerType()) )
  7232. {
  7233. if( !isMatchWithBaseType ) matches.SetLength(0);
  7234. isMatchWithBaseType = true;
  7235. matches.PushLast(funcs[n]);
  7236. continue;
  7237. }
  7238. if( !isMatchWithBaseType )
  7239. {
  7240. // Conversion between signed and unsigned integer is better than between integer and float
  7241. // Is it a match except for sign?
  7242. if( (argType->dataType.IsIntegerType() && ti.type.dataType.IsUnsignedType()) ||
  7243. (argType->dataType.IsUnsignedType() && ti.type.dataType.IsIntegerType()) ||
  7244. (argType->dataType.IsEnumType() && ti.type.dataType.IsUnsignedType()) )
  7245. {
  7246. if( !isMatchExceptSign ) matches.SetLength(0);
  7247. isMatchExceptSign = true;
  7248. matches.PushLast(funcs[n]);
  7249. continue;
  7250. }
  7251. if( !isMatchExceptSign )
  7252. {
  7253. // If there was any match without a var type it has higher priority
  7254. if( desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7255. {
  7256. if( !isMatchNotVarType ) matches.SetLength(0);
  7257. isMatchNotVarType = true;
  7258. matches.PushLast(funcs[n]);
  7259. continue;
  7260. }
  7261. // Implicit conversion to ?& has the smallest priority
  7262. if( !isMatchNotVarType )
  7263. matches.PushLast(funcs[n]);
  7264. }
  7265. }
  7266. }
  7267. }
  7268. }
  7269. }
  7270. return (int)matches.GetLength();
  7271. }
  7272. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, asCArray<int> *reservedVars)
  7273. {
  7274. // Reference parameters whose value won't be used don't evaluate the expression
  7275. if( paramType->IsReference() && !(refType & asTM_INREF) )
  7276. {
  7277. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  7278. asSExprContext *orig = asNEW(asSExprContext)(engine);
  7279. MergeExprBytecodeAndType(orig, arg);
  7280. arg->origExpr = orig;
  7281. }
  7282. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, reservedVars);
  7283. // arg still holds the original expression for output parameters
  7284. ctx->bc.AddCode(&arg->bc);
  7285. }
  7286. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7287. {
  7288. ctx->exprNode = node;
  7289. // What type of operator is it?
  7290. int token = node->tokenType;
  7291. if( token == ttUnrecognizedToken )
  7292. {
  7293. // This happens when the compiler is inferring an assignment
  7294. // operation from another action, for example in preparing a value
  7295. // as a function argument
  7296. token = ttAssignment;
  7297. }
  7298. // boolean operators are not overloadable
  7299. if( token == ttAnd ||
  7300. token == ttOr ||
  7301. token == ttXor )
  7302. return false;
  7303. // Dual operators can also be implemented as class methods
  7304. if( token == ttEqual ||
  7305. token == ttNotEqual )
  7306. {
  7307. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7308. // Find the matching opEquals method
  7309. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7310. if( r == 0 )
  7311. {
  7312. // Try again by switching the order of the operands
  7313. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7314. }
  7315. if( r == 1 )
  7316. {
  7317. if( token == ttNotEqual )
  7318. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7319. // Success, don't continue
  7320. return true;
  7321. }
  7322. else if( r < 0 )
  7323. {
  7324. // Compiler error, don't continue
  7325. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7326. return true;
  7327. }
  7328. }
  7329. if( token == ttEqual ||
  7330. token == ttNotEqual ||
  7331. token == ttLessThan ||
  7332. token == ttLessThanOrEqual ||
  7333. token == ttGreaterThan ||
  7334. token == ttGreaterThanOrEqual )
  7335. {
  7336. bool swappedOrder = false;
  7337. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7338. // Find the matching opCmp method
  7339. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7340. if( r == 0 )
  7341. {
  7342. // Try again by switching the order of the operands
  7343. swappedOrder = true;
  7344. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7345. }
  7346. if( r == 1 )
  7347. {
  7348. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7349. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  7350. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  7351. if( token == ttEqual )
  7352. ctx->bc.Instr(asBC_TZ);
  7353. else if( token == ttNotEqual )
  7354. ctx->bc.Instr(asBC_TNZ);
  7355. else if( (token == ttLessThan && !swappedOrder) ||
  7356. (token == ttGreaterThan && swappedOrder) )
  7357. ctx->bc.Instr(asBC_TS);
  7358. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  7359. (token == ttGreaterThanOrEqual && swappedOrder) )
  7360. ctx->bc.Instr(asBC_TNP);
  7361. else if( (token == ttGreaterThan && !swappedOrder) ||
  7362. (token == ttLessThan && swappedOrder) )
  7363. ctx->bc.Instr(asBC_TP);
  7364. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  7365. (token == ttLessThanOrEqual && swappedOrder) )
  7366. ctx->bc.Instr(asBC_TNS);
  7367. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  7368. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  7369. // Success, don't continue
  7370. return true;
  7371. }
  7372. else if( r < 0 )
  7373. {
  7374. // Compiler error, don't continue
  7375. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7376. return true;
  7377. }
  7378. }
  7379. // The rest of the operators are not commutative, and doesn't require specific return type
  7380. const char *op = 0, *op_r = 0;
  7381. switch( token )
  7382. {
  7383. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  7384. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  7385. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  7386. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  7387. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  7388. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  7389. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  7390. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  7391. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  7392. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  7393. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  7394. }
  7395. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  7396. if( op && op_r )
  7397. {
  7398. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7399. // Find the matching operator method
  7400. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7401. if( r == 0 )
  7402. {
  7403. // Try again by switching the order of the operands, and using the reversed operator
  7404. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  7405. }
  7406. if( r == 1 )
  7407. {
  7408. // Success, don't continue
  7409. return true;
  7410. }
  7411. else if( r < 0 )
  7412. {
  7413. // Compiler error, don't continue
  7414. ctx->type.SetDummy();
  7415. return true;
  7416. }
  7417. }
  7418. // Assignment operators
  7419. op = 0;
  7420. switch( token )
  7421. {
  7422. case ttAssignment: op = "opAssign"; break;
  7423. case ttAddAssign: op = "opAddAssign"; break;
  7424. case ttSubAssign: op = "opSubAssign"; break;
  7425. case ttMulAssign: op = "opMulAssign"; break;
  7426. case ttDivAssign: op = "opDivAssign"; break;
  7427. case ttModAssign: op = "opModAssign"; break;
  7428. case ttOrAssign: op = "opOrAssign"; break;
  7429. case ttAndAssign: op = "opAndAssign"; break;
  7430. case ttXorAssign: op = "opXorAssign"; break;
  7431. case ttShiftLeftAssign: op = "opShlAssign"; break;
  7432. case ttShiftRightLAssign: op = "opShrAssign"; break;
  7433. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  7434. }
  7435. if( op )
  7436. {
  7437. // TODO: Shouldn't accept const lvalue with the assignment operators
  7438. // Find the matching operator method
  7439. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7440. if( r == 1 )
  7441. {
  7442. // Success, don't continue
  7443. return true;
  7444. }
  7445. else if( r < 0 )
  7446. {
  7447. // Compiler error, don't continue
  7448. ctx->type.SetDummy();
  7449. return true;
  7450. }
  7451. }
  7452. // No suitable operator was found
  7453. return false;
  7454. }
  7455. // Returns negative on compile error
  7456. // zero on no matching operator
  7457. // one on matching operator
  7458. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  7459. {
  7460. // Find the matching method
  7461. if( lctx->type.dataType.IsObject() && !lctx->type.isExplicitHandle )
  7462. {
  7463. // Is the left value a const?
  7464. bool isConst = false;
  7465. if( lctx->type.dataType.IsObjectHandle() )
  7466. isConst = lctx->type.dataType.IsHandleToConst();
  7467. else
  7468. isConst = lctx->type.dataType.IsReadOnly();
  7469. asCArray<int> funcs;
  7470. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  7471. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7472. {
  7473. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7474. if( func->name == methodName &&
  7475. (!specificReturn || func->returnType == returnType) &&
  7476. func->parameterTypes.GetLength() == 1 &&
  7477. (!isConst || func->isReadOnly) )
  7478. {
  7479. // Make sure the method is accessible by the module
  7480. asCConfigGroup *group = engine->FindConfigGroupForFunction(func->id);
  7481. if( !group || group->HasModuleAccess(builder->module->name.AddressOf()) )
  7482. funcs.PushLast(func->id);
  7483. }
  7484. }
  7485. // Which is the best matching function?
  7486. asCArray<int> ops;
  7487. MatchArgument(funcs, ops, &rctx->type, 0);
  7488. // If the object is not const, then we need to prioritize non-const methods
  7489. if( !isConst )
  7490. FilterConst(ops);
  7491. // Did we find an operator?
  7492. if( ops.GetLength() == 1 )
  7493. {
  7494. // Process the lctx expression as get accessor
  7495. ProcessPropertyGetAccessor(lctx, node);
  7496. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  7497. asCTypeInfo objType = lctx->type;
  7498. asCArray<asSExprContext *> args;
  7499. args.PushLast(rctx);
  7500. MergeExprBytecode(ctx, lctx);
  7501. ctx->type = lctx->type;
  7502. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  7503. // If the method returned a reference, then we can't release the original
  7504. // object yet, because the reference may be to a member of it
  7505. if( objType.isTemporary &&
  7506. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7507. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  7508. {
  7509. // Remember the object's variable, so that it can be released
  7510. // later on when the reference to its member goes out of scope
  7511. ctx->type.isTemporary = true;
  7512. ctx->type.stackOffset = objType.stackOffset;
  7513. }
  7514. else
  7515. {
  7516. // As the index operator didn't return a reference to a
  7517. // member we can release the original object now
  7518. ReleaseTemporaryVariable(objType, &ctx->bc);
  7519. }
  7520. // Found matching operator
  7521. return 1;
  7522. }
  7523. else if( ops.GetLength() > 1 )
  7524. {
  7525. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7526. PrintMatchingFuncs(ops, node);
  7527. ctx->type.SetDummy();
  7528. // Compiler error
  7529. return -1;
  7530. }
  7531. }
  7532. // No matching operator
  7533. return 0;
  7534. }
  7535. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  7536. {
  7537. if( objectType )
  7538. {
  7539. Dereference(ctx, true);
  7540. // Warn if the method is non-const and the object is temporary
  7541. // since the changes will be lost when the object is destroyed.
  7542. // If the object is accessed through a handle, then it is assumed
  7543. // the object is not temporary, even though the handle is.
  7544. if( ctx->type.isTemporary &&
  7545. !ctx->type.dataType.IsObjectHandle() &&
  7546. !engine->scriptFunctions[funcId]->isReadOnly )
  7547. {
  7548. Warning(TXT_CALLING_NONCONST_METHOD_ON_TEMP, node);
  7549. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  7550. }
  7551. }
  7552. asCByteCode objBC(engine);
  7553. objBC.AddCode(&ctx->bc);
  7554. PrepareFunctionCall(funcId, &ctx->bc, args);
  7555. // Verify if any of the args variable offsets are used in the other code.
  7556. // If they are exchange the offset for a new one
  7557. asUINT n;
  7558. for( n = 0; n < args.GetLength(); n++ )
  7559. {
  7560. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  7561. {
  7562. // Release the current temporary variable
  7563. ReleaseTemporaryVariable(args[n]->type, 0);
  7564. asCArray<int> usedVars;
  7565. objBC.GetVarsUsed(usedVars);
  7566. ctx->bc.GetVarsUsed(usedVars);
  7567. asCDataType dt = args[n]->type.dataType;
  7568. dt.MakeReference(false);
  7569. int newOffset = AllocateVariableNotIn(dt, true, &usedVars, IsVariableOnHeap(args[n]->type.stackOffset));
  7570. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  7571. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  7572. args[n]->type.stackOffset = (short)newOffset;
  7573. args[n]->type.isTemporary = true;
  7574. args[n]->type.isVariable = true;
  7575. }
  7576. }
  7577. ctx->bc.AddCode(&objBC);
  7578. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  7579. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  7580. }
  7581. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7582. {
  7583. IsVariableInitialized(&lctx->type, node);
  7584. IsVariableInitialized(&rctx->type, node);
  7585. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  7586. node->tokenType == ttIs || node->tokenType == ttNotIs )
  7587. {
  7588. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  7589. return 0;
  7590. }
  7591. else
  7592. {
  7593. // Compile an overloaded operator for the two operands
  7594. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  7595. return 0;
  7596. // If both operands are objects, then we shouldn't continue
  7597. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  7598. {
  7599. asCString str;
  7600. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  7601. Error(str.AddressOf(), node);
  7602. ctx->type.SetDummy();
  7603. return -1;
  7604. }
  7605. // Make sure we have two variables or constants
  7606. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  7607. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  7608. // Process the property get accessors (if any)
  7609. ProcessPropertyGetAccessor(lctx, node);
  7610. ProcessPropertyGetAccessor(rctx, node);
  7611. // Make sure lctx doesn't end up with a variable used in rctx
  7612. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  7613. {
  7614. asCArray<int> vars;
  7615. rctx->bc.GetVarsUsed(vars);
  7616. int offset = AllocateVariableNotIn(lctx->type.dataType, true, &vars);
  7617. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  7618. ReleaseTemporaryVariable(offset, 0);
  7619. }
  7620. // Math operators
  7621. // + - * / % += -= *= /= %=
  7622. int op = node->tokenType;
  7623. if( op == ttPlus || op == ttAddAssign ||
  7624. op == ttMinus || op == ttSubAssign ||
  7625. op == ttStar || op == ttMulAssign ||
  7626. op == ttSlash || op == ttDivAssign ||
  7627. op == ttPercent || op == ttModAssign )
  7628. {
  7629. CompileMathOperator(node, lctx, rctx, ctx);
  7630. return 0;
  7631. }
  7632. // Bitwise operators
  7633. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  7634. if( op == ttAmp || op == ttAndAssign ||
  7635. op == ttBitOr || op == ttOrAssign ||
  7636. op == ttBitXor || op == ttXorAssign ||
  7637. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  7638. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  7639. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  7640. {
  7641. CompileBitwiseOperator(node, lctx, rctx, ctx);
  7642. return 0;
  7643. }
  7644. // Comparison operators
  7645. // == != < > <= >=
  7646. if( op == ttEqual || op == ttNotEqual ||
  7647. op == ttLessThan || op == ttLessThanOrEqual ||
  7648. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  7649. {
  7650. CompileComparisonOperator(node, lctx, rctx, ctx);
  7651. return 0;
  7652. }
  7653. // Boolean operators
  7654. // && || ^^
  7655. if( op == ttAnd || op == ttOr || op == ttXor )
  7656. {
  7657. CompileBooleanOperator(node, lctx, rctx, ctx);
  7658. return 0;
  7659. }
  7660. }
  7661. asASSERT(false);
  7662. return -1;
  7663. }
  7664. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  7665. {
  7666. asCArray<int> excludeVars;
  7667. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  7668. ConvertToTempVariableNotIn(ctx, &excludeVars);
  7669. }
  7670. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  7671. {
  7672. // This is only used for primitive types and null handles
  7673. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  7674. ConvertToVariableNotIn(ctx, reservedVars);
  7675. if( !ctx->type.isTemporary )
  7676. {
  7677. if( ctx->type.dataType.IsPrimitive() )
  7678. {
  7679. // Copy the variable to a temporary variable
  7680. int offset = AllocateVariableNotIn(ctx->type.dataType, true, reservedVars);
  7681. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7682. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  7683. else
  7684. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  7685. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7686. }
  7687. else
  7688. {
  7689. // We should never get here
  7690. asASSERT(false);
  7691. }
  7692. }
  7693. }
  7694. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  7695. {
  7696. ConvertToTempVariableNotIn(ctx, (asCArray<int>*)0);
  7697. }
  7698. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  7699. {
  7700. ConvertToVariableNotIn(ctx, (asCArray<int>*)0);
  7701. }
  7702. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  7703. {
  7704. asCArray<int> excludeVars;
  7705. if( reservedVars ) excludeVars.Concatenate(*reservedVars);
  7706. int offset;
  7707. if( !ctx->type.isVariable &&
  7708. (ctx->type.dataType.IsObjectHandle() ||
  7709. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  7710. {
  7711. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7712. if( ctx->type.IsNullConstant() )
  7713. {
  7714. #ifdef AS_64BIT_PTR
  7715. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, 0);
  7716. #else
  7717. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, 0);
  7718. #endif
  7719. }
  7720. else
  7721. {
  7722. // Copy the object handle to a variable
  7723. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7724. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  7725. ctx->bc.Pop(AS_PTR_SIZE);
  7726. }
  7727. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7728. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7729. ctx->type.dataType.MakeHandle(true);
  7730. }
  7731. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  7732. ctx->type.dataType.IsPrimitive() )
  7733. {
  7734. if( ctx->type.isConstant )
  7735. {
  7736. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7737. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7738. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  7739. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7740. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  7741. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7742. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  7743. else
  7744. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  7745. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7746. return;
  7747. }
  7748. else
  7749. {
  7750. asASSERT(ctx->type.dataType.IsPrimitive());
  7751. asASSERT(ctx->type.dataType.IsReference());
  7752. ctx->type.dataType.MakeReference(false);
  7753. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7754. // Read the value from the address in the register directly into the variable
  7755. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7756. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  7757. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7758. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  7759. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7760. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  7761. else
  7762. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  7763. }
  7764. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7765. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7766. }
  7767. }
  7768. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  7769. {
  7770. asCArray<int> excludeVars;
  7771. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  7772. ConvertToVariableNotIn(ctx, &excludeVars);
  7773. }
  7774. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7775. {
  7776. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  7777. // Implicitly convert the operands to a number type
  7778. asCDataType to;
  7779. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  7780. to.SetTokenType(ttDouble);
  7781. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  7782. to.SetTokenType(ttFloat);
  7783. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7784. {
  7785. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  7786. to.SetTokenType(ttInt64);
  7787. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  7788. to.SetTokenType(ttUInt64);
  7789. }
  7790. else
  7791. {
  7792. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  7793. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  7794. to.SetTokenType(ttInt);
  7795. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  7796. to.SetTokenType(ttUInt);
  7797. }
  7798. // If doing an operation with double constant and float variable, the constant should be converted to float
  7799. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  7800. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  7801. to.SetTokenType(ttFloat);
  7802. // Do the actual conversion
  7803. asCArray<int> reservedVars;
  7804. rctx->bc.GetVarsUsed(reservedVars);
  7805. lctx->bc.GetVarsUsed(reservedVars);
  7806. if( lctx->type.dataType.IsReference() )
  7807. ConvertToVariableNotIn(lctx, &reservedVars);
  7808. if( rctx->type.dataType.IsReference() )
  7809. ConvertToVariableNotIn(rctx, &reservedVars);
  7810. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  7811. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  7812. // Verify that the conversion was successful
  7813. if( !lctx->type.dataType.IsIntegerType() &&
  7814. !lctx->type.dataType.IsUnsignedType() &&
  7815. !lctx->type.dataType.IsFloatType() &&
  7816. !lctx->type.dataType.IsDoubleType() )
  7817. {
  7818. asCString str;
  7819. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  7820. Error(str.AddressOf(), node);
  7821. ctx->type.SetDummy();
  7822. return;
  7823. }
  7824. if( !rctx->type.dataType.IsIntegerType() &&
  7825. !rctx->type.dataType.IsUnsignedType() &&
  7826. !rctx->type.dataType.IsFloatType() &&
  7827. !rctx->type.dataType.IsDoubleType() )
  7828. {
  7829. asCString str;
  7830. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  7831. Error(str.AddressOf(), node);
  7832. ctx->type.SetDummy();
  7833. return;
  7834. }
  7835. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  7836. // Verify if we are dividing with a constant zero
  7837. int op = node->tokenType;
  7838. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  7839. (op == ttSlash || op == ttDivAssign ||
  7840. op == ttPercent || op == ttModAssign) )
  7841. {
  7842. Error(TXT_DIVIDE_BY_ZERO, node);
  7843. }
  7844. if( !isConstant )
  7845. {
  7846. ConvertToVariableNotIn(lctx, rctx);
  7847. ConvertToVariableNotIn(rctx, lctx);
  7848. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  7849. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  7850. if( op == ttAddAssign || op == ttSubAssign ||
  7851. op == ttMulAssign || op == ttDivAssign ||
  7852. op == ttModAssign )
  7853. {
  7854. // Merge the operands in the different order so that they are evaluated correctly
  7855. MergeExprBytecode(ctx, rctx);
  7856. MergeExprBytecode(ctx, lctx);
  7857. }
  7858. else
  7859. {
  7860. MergeExprBytecode(ctx, lctx);
  7861. MergeExprBytecode(ctx, rctx);
  7862. }
  7863. ProcessDeferredParams(ctx);
  7864. asEBCInstr instruction = asBC_ADDi;
  7865. if( lctx->type.dataType.IsIntegerType() ||
  7866. lctx->type.dataType.IsUnsignedType() )
  7867. {
  7868. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7869. {
  7870. if( op == ttPlus || op == ttAddAssign )
  7871. instruction = asBC_ADDi;
  7872. else if( op == ttMinus || op == ttSubAssign )
  7873. instruction = asBC_SUBi;
  7874. else if( op == ttStar || op == ttMulAssign )
  7875. instruction = asBC_MULi;
  7876. else if( op == ttSlash || op == ttDivAssign )
  7877. {
  7878. if( lctx->type.dataType.IsIntegerType() )
  7879. instruction = asBC_DIVi;
  7880. else
  7881. instruction = asBC_DIVu;
  7882. }
  7883. else if( op == ttPercent || op == ttModAssign )
  7884. {
  7885. if( lctx->type.dataType.IsIntegerType() )
  7886. instruction = asBC_MODi;
  7887. else
  7888. instruction = asBC_MODu;
  7889. }
  7890. }
  7891. else
  7892. {
  7893. if( op == ttPlus || op == ttAddAssign )
  7894. instruction = asBC_ADDi64;
  7895. else if( op == ttMinus || op == ttSubAssign )
  7896. instruction = asBC_SUBi64;
  7897. else if( op == ttStar || op == ttMulAssign )
  7898. instruction = asBC_MULi64;
  7899. else if( op == ttSlash || op == ttDivAssign )
  7900. {
  7901. if( lctx->type.dataType.IsIntegerType() )
  7902. instruction = asBC_DIVi64;
  7903. else
  7904. instruction = asBC_DIVu64;
  7905. }
  7906. else if( op == ttPercent || op == ttModAssign )
  7907. {
  7908. if( lctx->type.dataType.IsIntegerType() )
  7909. instruction = asBC_MODi64;
  7910. else
  7911. instruction = asBC_MODu64;
  7912. }
  7913. }
  7914. }
  7915. else if( lctx->type.dataType.IsFloatType() )
  7916. {
  7917. if( op == ttPlus || op == ttAddAssign )
  7918. instruction = asBC_ADDf;
  7919. else if( op == ttMinus || op == ttSubAssign )
  7920. instruction = asBC_SUBf;
  7921. else if( op == ttStar || op == ttMulAssign )
  7922. instruction = asBC_MULf;
  7923. else if( op == ttSlash || op == ttDivAssign )
  7924. instruction = asBC_DIVf;
  7925. else if( op == ttPercent || op == ttModAssign )
  7926. instruction = asBC_MODf;
  7927. }
  7928. else if( lctx->type.dataType.IsDoubleType() )
  7929. {
  7930. if( op == ttPlus || op == ttAddAssign )
  7931. instruction = asBC_ADDd;
  7932. else if( op == ttMinus || op == ttSubAssign )
  7933. instruction = asBC_SUBd;
  7934. else if( op == ttStar || op == ttMulAssign )
  7935. instruction = asBC_MULd;
  7936. else if( op == ttSlash || op == ttDivAssign )
  7937. instruction = asBC_DIVd;
  7938. else if( op == ttPercent || op == ttModAssign )
  7939. instruction = asBC_MODd;
  7940. }
  7941. else
  7942. {
  7943. // Shouldn't be possible
  7944. asASSERT(false);
  7945. }
  7946. // Do the operation
  7947. int a = AllocateVariable(lctx->type.dataType, true);
  7948. int b = lctx->type.stackOffset;
  7949. int c = rctx->type.stackOffset;
  7950. ctx->bc.InstrW_W_W(instruction, a, b, c);
  7951. ctx->type.SetVariable(lctx->type.dataType, a, true);
  7952. }
  7953. else
  7954. {
  7955. // Both values are constants
  7956. if( lctx->type.dataType.IsIntegerType() ||
  7957. lctx->type.dataType.IsUnsignedType() )
  7958. {
  7959. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7960. {
  7961. int v = 0;
  7962. if( op == ttPlus )
  7963. v = lctx->type.intValue + rctx->type.intValue;
  7964. else if( op == ttMinus )
  7965. v = lctx->type.intValue - rctx->type.intValue;
  7966. else if( op == ttStar )
  7967. v = lctx->type.intValue * rctx->type.intValue;
  7968. else if( op == ttSlash )
  7969. {
  7970. if( rctx->type.intValue == 0 )
  7971. v = 0;
  7972. else
  7973. if( lctx->type.dataType.IsIntegerType() )
  7974. v = lctx->type.intValue / rctx->type.intValue;
  7975. else
  7976. v = lctx->type.dwordValue / rctx->type.dwordValue;
  7977. }
  7978. else if( op == ttPercent )
  7979. {
  7980. if( rctx->type.intValue == 0 )
  7981. v = 0;
  7982. else
  7983. if( lctx->type.dataType.IsIntegerType() )
  7984. v = lctx->type.intValue % rctx->type.intValue;
  7985. else
  7986. v = lctx->type.dwordValue % rctx->type.dwordValue;
  7987. }
  7988. ctx->type.SetConstantDW(lctx->type.dataType, v);
  7989. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  7990. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  7991. ctx->type.dataType.SetTokenType(ttInt);
  7992. }
  7993. else
  7994. {
  7995. asQWORD v = 0;
  7996. if( op == ttPlus )
  7997. v = lctx->type.qwordValue + rctx->type.qwordValue;
  7998. else if( op == ttMinus )
  7999. v = lctx->type.qwordValue - rctx->type.qwordValue;
  8000. else if( op == ttStar )
  8001. v = lctx->type.qwordValue * rctx->type.qwordValue;
  8002. else if( op == ttSlash )
  8003. {
  8004. if( rctx->type.qwordValue == 0 )
  8005. v = 0;
  8006. else
  8007. if( lctx->type.dataType.IsIntegerType() )
  8008. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  8009. else
  8010. v = lctx->type.qwordValue / rctx->type.qwordValue;
  8011. }
  8012. else if( op == ttPercent )
  8013. {
  8014. if( rctx->type.qwordValue == 0 )
  8015. v = 0;
  8016. else
  8017. if( lctx->type.dataType.IsIntegerType() )
  8018. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  8019. else
  8020. v = lctx->type.qwordValue % rctx->type.qwordValue;
  8021. }
  8022. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8023. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8024. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  8025. ctx->type.dataType.SetTokenType(ttInt64);
  8026. }
  8027. }
  8028. else if( lctx->type.dataType.IsFloatType() )
  8029. {
  8030. float v = 0.0f;
  8031. if( op == ttPlus )
  8032. v = lctx->type.floatValue + rctx->type.floatValue;
  8033. else if( op == ttMinus )
  8034. v = lctx->type.floatValue - rctx->type.floatValue;
  8035. else if( op == ttStar )
  8036. v = lctx->type.floatValue * rctx->type.floatValue;
  8037. else if( op == ttSlash )
  8038. {
  8039. if( rctx->type.floatValue == 0 )
  8040. v = 0;
  8041. else
  8042. v = lctx->type.floatValue / rctx->type.floatValue;
  8043. }
  8044. else if( op == ttPercent )
  8045. {
  8046. if( rctx->type.floatValue == 0 )
  8047. v = 0;
  8048. else
  8049. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  8050. }
  8051. ctx->type.SetConstantF(lctx->type.dataType, v);
  8052. }
  8053. else if( lctx->type.dataType.IsDoubleType() )
  8054. {
  8055. double v = 0.0;
  8056. if( op == ttPlus )
  8057. v = lctx->type.doubleValue + rctx->type.doubleValue;
  8058. else if( op == ttMinus )
  8059. v = lctx->type.doubleValue - rctx->type.doubleValue;
  8060. else if( op == ttStar )
  8061. v = lctx->type.doubleValue * rctx->type.doubleValue;
  8062. else if( op == ttSlash )
  8063. {
  8064. if( rctx->type.doubleValue == 0 )
  8065. v = 0;
  8066. else
  8067. v = lctx->type.doubleValue / rctx->type.doubleValue;
  8068. }
  8069. else if( op == ttPercent )
  8070. {
  8071. if( rctx->type.doubleValue == 0 )
  8072. v = 0;
  8073. else
  8074. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  8075. }
  8076. ctx->type.SetConstantD(lctx->type.dataType, v);
  8077. }
  8078. else
  8079. {
  8080. // Shouldn't be possible
  8081. asASSERT(false);
  8082. }
  8083. }
  8084. }
  8085. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8086. {
  8087. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8088. int op = node->tokenType;
  8089. if( op == ttAmp || op == ttAndAssign ||
  8090. op == ttBitOr || op == ttOrAssign ||
  8091. op == ttBitXor || op == ttXorAssign )
  8092. {
  8093. // Convert left hand operand to integer if it's not already one
  8094. asCDataType to;
  8095. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  8096. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8097. to.SetTokenType(ttUInt64);
  8098. else
  8099. to.SetTokenType(ttUInt);
  8100. // Do the actual conversion
  8101. asCArray<int> reservedVars;
  8102. rctx->bc.GetVarsUsed(reservedVars);
  8103. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8104. // Verify that the conversion was successful
  8105. if( !lctx->type.dataType.IsUnsignedType() )
  8106. {
  8107. asCString str;
  8108. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8109. Error(str.AddressOf(), node);
  8110. }
  8111. // Convert right hand operand to same type as left hand operand
  8112. asCArray<int> vars;
  8113. lctx->bc.GetVarsUsed(vars);
  8114. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true, &vars);
  8115. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  8116. {
  8117. asCString str;
  8118. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  8119. Error(str.AddressOf(), node);
  8120. }
  8121. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8122. if( !isConstant )
  8123. {
  8124. ConvertToVariableNotIn(lctx, rctx);
  8125. ConvertToVariableNotIn(rctx, lctx);
  8126. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8127. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8128. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  8129. {
  8130. // Compound assignments execute the right hand value first
  8131. MergeExprBytecode(ctx, rctx);
  8132. MergeExprBytecode(ctx, lctx);
  8133. }
  8134. else
  8135. {
  8136. MergeExprBytecode(ctx, lctx);
  8137. MergeExprBytecode(ctx, rctx);
  8138. }
  8139. ProcessDeferredParams(ctx);
  8140. asEBCInstr instruction = asBC_BAND;
  8141. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8142. {
  8143. if( op == ttAmp || op == ttAndAssign )
  8144. instruction = asBC_BAND;
  8145. else if( op == ttBitOr || op == ttOrAssign )
  8146. instruction = asBC_BOR;
  8147. else if( op == ttBitXor || op == ttXorAssign )
  8148. instruction = asBC_BXOR;
  8149. }
  8150. else
  8151. {
  8152. if( op == ttAmp || op == ttAndAssign )
  8153. instruction = asBC_BAND64;
  8154. else if( op == ttBitOr || op == ttOrAssign )
  8155. instruction = asBC_BOR64;
  8156. else if( op == ttBitXor || op == ttXorAssign )
  8157. instruction = asBC_BXOR64;
  8158. }
  8159. // Do the operation
  8160. int a = AllocateVariable(lctx->type.dataType, true);
  8161. int b = lctx->type.stackOffset;
  8162. int c = rctx->type.stackOffset;
  8163. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8164. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8165. }
  8166. else
  8167. {
  8168. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8169. {
  8170. asQWORD v = 0;
  8171. if( op == ttAmp )
  8172. v = lctx->type.qwordValue & rctx->type.qwordValue;
  8173. else if( op == ttBitOr )
  8174. v = lctx->type.qwordValue | rctx->type.qwordValue;
  8175. else if( op == ttBitXor )
  8176. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  8177. // Remember the result
  8178. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8179. }
  8180. else
  8181. {
  8182. asDWORD v = 0;
  8183. if( op == ttAmp )
  8184. v = lctx->type.dwordValue & rctx->type.dwordValue;
  8185. else if( op == ttBitOr )
  8186. v = lctx->type.dwordValue | rctx->type.dwordValue;
  8187. else if( op == ttBitXor )
  8188. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  8189. // Remember the result
  8190. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8191. }
  8192. }
  8193. }
  8194. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8195. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8196. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8197. {
  8198. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  8199. if( lctx->type.dataType.IsObject() )
  8200. {
  8201. asCString str;
  8202. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  8203. Error(str.AddressOf(), node);
  8204. // Set an integer value and allow the compiler to continue
  8205. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  8206. return;
  8207. }
  8208. // Convert left hand operand to integer if it's not already one
  8209. asCDataType to = lctx->type.dataType;
  8210. if( lctx->type.dataType.IsUnsignedType() &&
  8211. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  8212. {
  8213. to = asCDataType::CreatePrimitive(ttUInt, false);
  8214. }
  8215. else if( !lctx->type.dataType.IsUnsignedType() )
  8216. {
  8217. asCDataType to;
  8218. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8219. to.SetTokenType(ttInt64);
  8220. else
  8221. to.SetTokenType(ttInt);
  8222. }
  8223. // Do the actual conversion
  8224. asCArray<int> reservedVars;
  8225. rctx->bc.GetVarsUsed(reservedVars);
  8226. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8227. // Verify that the conversion was successful
  8228. if( lctx->type.dataType != to )
  8229. {
  8230. asCString str;
  8231. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8232. Error(str.AddressOf(), node);
  8233. }
  8234. // Right operand must be 32bit uint
  8235. asCArray<int> vars;
  8236. lctx->bc.GetVarsUsed(vars);
  8237. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true, &vars);
  8238. if( !rctx->type.dataType.IsUnsignedType() )
  8239. {
  8240. asCString str;
  8241. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  8242. Error(str.AddressOf(), node);
  8243. }
  8244. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8245. if( !isConstant )
  8246. {
  8247. ConvertToVariableNotIn(lctx, rctx);
  8248. ConvertToVariableNotIn(rctx, lctx);
  8249. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8250. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8251. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  8252. {
  8253. // Compound assignments execute the right hand value first
  8254. MergeExprBytecode(ctx, rctx);
  8255. MergeExprBytecode(ctx, lctx);
  8256. }
  8257. else
  8258. {
  8259. MergeExprBytecode(ctx, lctx);
  8260. MergeExprBytecode(ctx, rctx);
  8261. }
  8262. ProcessDeferredParams(ctx);
  8263. asEBCInstr instruction = asBC_BSLL;
  8264. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8265. {
  8266. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8267. instruction = asBC_BSLL;
  8268. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8269. instruction = asBC_BSRL;
  8270. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8271. instruction = asBC_BSRA;
  8272. }
  8273. else
  8274. {
  8275. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8276. instruction = asBC_BSLL64;
  8277. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8278. instruction = asBC_BSRL64;
  8279. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8280. instruction = asBC_BSRA64;
  8281. }
  8282. // Do the operation
  8283. int a = AllocateVariable(lctx->type.dataType, true);
  8284. int b = lctx->type.stackOffset;
  8285. int c = rctx->type.stackOffset;
  8286. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8287. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8288. }
  8289. else
  8290. {
  8291. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8292. {
  8293. asDWORD v = 0;
  8294. if( op == ttBitShiftLeft )
  8295. v = lctx->type.dwordValue << rctx->type.dwordValue;
  8296. else if( op == ttBitShiftRight )
  8297. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  8298. else if( op == ttBitShiftRightArith )
  8299. v = lctx->type.intValue >> rctx->type.dwordValue;
  8300. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8301. }
  8302. else
  8303. {
  8304. asQWORD v = 0;
  8305. if( op == ttBitShiftLeft )
  8306. v = lctx->type.qwordValue << rctx->type.dwordValue;
  8307. else if( op == ttBitShiftRight )
  8308. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  8309. else if( op == ttBitShiftRightArith )
  8310. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  8311. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8312. }
  8313. }
  8314. }
  8315. }
  8316. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8317. {
  8318. // Both operands must be of the same type
  8319. // Implicitly convert the operands to a number type
  8320. asCDataType to;
  8321. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8322. to.SetTokenType(ttDouble);
  8323. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8324. to.SetTokenType(ttFloat);
  8325. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8326. {
  8327. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8328. to.SetTokenType(ttInt64);
  8329. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8330. to.SetTokenType(ttUInt64);
  8331. }
  8332. else
  8333. {
  8334. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8335. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8336. to.SetTokenType(ttInt);
  8337. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8338. to.SetTokenType(ttUInt);
  8339. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  8340. to.SetTokenType(ttBool);
  8341. }
  8342. // If doing an operation with double constant and float variable, the constant should be converted to float
  8343. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8344. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8345. to.SetTokenType(ttFloat);
  8346. // Is it an operation on signed values?
  8347. bool signMismatch = false;
  8348. if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
  8349. {
  8350. if( lctx->type.dataType.GetTokenType() == ttUInt64 )
  8351. {
  8352. if( !lctx->type.isConstant )
  8353. signMismatch = true;
  8354. else if( lctx->type.qwordValue & (I64(1)<<63) )
  8355. signMismatch = true;
  8356. }
  8357. if( lctx->type.dataType.GetTokenType() == ttUInt )
  8358. {
  8359. if( !lctx->type.isConstant )
  8360. signMismatch = true;
  8361. else if( lctx->type.dwordValue & (1<<31) )
  8362. signMismatch = true;
  8363. }
  8364. if( rctx->type.dataType.GetTokenType() == ttUInt64 )
  8365. {
  8366. if( !rctx->type.isConstant )
  8367. signMismatch = true;
  8368. else if( rctx->type.qwordValue & (I64(1)<<63) )
  8369. signMismatch = true;
  8370. }
  8371. if( rctx->type.dataType.GetTokenType() == ttUInt )
  8372. {
  8373. if( !rctx->type.isConstant )
  8374. signMismatch = true;
  8375. else if( rctx->type.dwordValue & (1<<31) )
  8376. signMismatch = true;
  8377. }
  8378. }
  8379. // Check for signed/unsigned mismatch
  8380. if( signMismatch )
  8381. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  8382. // Do the actual conversion
  8383. asCArray<int> reservedVars;
  8384. rctx->bc.GetVarsUsed(reservedVars);
  8385. if( lctx->type.dataType.IsReference() )
  8386. ConvertToVariableNotIn(lctx, &reservedVars);
  8387. if( rctx->type.dataType.IsReference() )
  8388. ConvertToVariableNotIn(rctx, &reservedVars);
  8389. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8390. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8391. // Verify that the conversion was successful
  8392. bool ok = true;
  8393. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8394. {
  8395. asCString str;
  8396. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8397. Error(str.AddressOf(), node);
  8398. ok = false;
  8399. }
  8400. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8401. {
  8402. asCString str;
  8403. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8404. Error(str.AddressOf(), node);
  8405. ok = false;
  8406. }
  8407. if( !ok )
  8408. {
  8409. // It wasn't possible to get two valid operands, so we just return
  8410. // a boolean result and let the compiler continue.
  8411. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8412. return;
  8413. }
  8414. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8415. int op = node->tokenType;
  8416. if( !isConstant )
  8417. {
  8418. if( to.IsBooleanType() )
  8419. {
  8420. int op = node->tokenType;
  8421. if( op == ttEqual || op == ttNotEqual )
  8422. {
  8423. // Must convert to temporary variable, because we are changing the value before comparison
  8424. ConvertToTempVariableNotIn(lctx, rctx);
  8425. ConvertToTempVariableNotIn(rctx, lctx);
  8426. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8427. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8428. // Make sure they are equal if not false
  8429. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8430. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8431. MergeExprBytecode(ctx, lctx);
  8432. MergeExprBytecode(ctx, rctx);
  8433. ProcessDeferredParams(ctx);
  8434. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8435. int b = lctx->type.stackOffset;
  8436. int c = rctx->type.stackOffset;
  8437. if( op == ttEqual )
  8438. {
  8439. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8440. ctx->bc.Instr(asBC_TZ);
  8441. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8442. }
  8443. else if( op == ttNotEqual )
  8444. {
  8445. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8446. ctx->bc.Instr(asBC_TNZ);
  8447. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8448. }
  8449. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8450. }
  8451. else
  8452. {
  8453. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8454. Error(TXT_ILLEGAL_OPERATION, node);
  8455. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  8456. }
  8457. }
  8458. else
  8459. {
  8460. ConvertToVariableNotIn(lctx, rctx);
  8461. ConvertToVariableNotIn(rctx, lctx);
  8462. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8463. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8464. MergeExprBytecode(ctx, lctx);
  8465. MergeExprBytecode(ctx, rctx);
  8466. ProcessDeferredParams(ctx);
  8467. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  8468. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8469. iCmp = asBC_CMPi;
  8470. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8471. iCmp = asBC_CMPu;
  8472. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8473. iCmp = asBC_CMPi64;
  8474. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8475. iCmp = asBC_CMPu64;
  8476. else if( lctx->type.dataType.IsFloatType() )
  8477. iCmp = asBC_CMPf;
  8478. else if( lctx->type.dataType.IsDoubleType() )
  8479. iCmp = asBC_CMPd;
  8480. else
  8481. asASSERT(false);
  8482. if( op == ttEqual )
  8483. iT = asBC_TZ;
  8484. else if( op == ttNotEqual )
  8485. iT = asBC_TNZ;
  8486. else if( op == ttLessThan )
  8487. iT = asBC_TS;
  8488. else if( op == ttLessThanOrEqual )
  8489. iT = asBC_TNP;
  8490. else if( op == ttGreaterThan )
  8491. iT = asBC_TP;
  8492. else if( op == ttGreaterThanOrEqual )
  8493. iT = asBC_TNS;
  8494. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8495. int b = lctx->type.stackOffset;
  8496. int c = rctx->type.stackOffset;
  8497. ctx->bc.InstrW_W(iCmp, b, c);
  8498. ctx->bc.Instr(iT);
  8499. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8500. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8501. }
  8502. }
  8503. else
  8504. {
  8505. if( to.IsBooleanType() )
  8506. {
  8507. int op = node->tokenType;
  8508. if( op == ttEqual || op == ttNotEqual )
  8509. {
  8510. // Make sure they are equal if not false
  8511. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8512. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8513. asDWORD v = 0;
  8514. if( op == ttEqual )
  8515. {
  8516. v = lctx->type.intValue - rctx->type.intValue;
  8517. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8518. }
  8519. else if( op == ttNotEqual )
  8520. {
  8521. v = lctx->type.intValue - rctx->type.intValue;
  8522. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8523. }
  8524. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  8525. }
  8526. else
  8527. {
  8528. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8529. Error(TXT_ILLEGAL_OPERATION, node);
  8530. }
  8531. }
  8532. else
  8533. {
  8534. int i = 0;
  8535. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8536. {
  8537. int v = lctx->type.intValue - rctx->type.intValue;
  8538. if( v < 0 ) i = -1;
  8539. if( v > 0 ) i = 1;
  8540. }
  8541. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8542. {
  8543. asDWORD v1 = lctx->type.dwordValue;
  8544. asDWORD v2 = rctx->type.dwordValue;
  8545. if( v1 < v2 ) i = -1;
  8546. if( v1 > v2 ) i = 1;
  8547. }
  8548. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8549. {
  8550. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  8551. if( v < 0 ) i = -1;
  8552. if( v > 0 ) i = 1;
  8553. }
  8554. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8555. {
  8556. asQWORD v1 = lctx->type.qwordValue;
  8557. asQWORD v2 = rctx->type.qwordValue;
  8558. if( v1 < v2 ) i = -1;
  8559. if( v1 > v2 ) i = 1;
  8560. }
  8561. else if( lctx->type.dataType.IsFloatType() )
  8562. {
  8563. float v = lctx->type.floatValue - rctx->type.floatValue;
  8564. if( v < 0 ) i = -1;
  8565. if( v > 0 ) i = 1;
  8566. }
  8567. else if( lctx->type.dataType.IsDoubleType() )
  8568. {
  8569. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  8570. if( v < 0 ) i = -1;
  8571. if( v > 0 ) i = 1;
  8572. }
  8573. if( op == ttEqual )
  8574. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8575. else if( op == ttNotEqual )
  8576. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8577. else if( op == ttLessThan )
  8578. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8579. else if( op == ttLessThanOrEqual )
  8580. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8581. else if( op == ttGreaterThan )
  8582. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8583. else if( op == ttGreaterThanOrEqual )
  8584. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8585. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  8586. }
  8587. }
  8588. }
  8589. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  8590. {
  8591. // Put the result on the stack
  8592. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  8593. if( asReference )
  8594. ctx->type.dataType.MakeReference(true);
  8595. else
  8596. {
  8597. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8598. ctx->bc.Instr(asBC_RDS4);
  8599. else
  8600. ctx->bc.Instr(asBC_RDS8);
  8601. }
  8602. }
  8603. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8604. {
  8605. // Both operands must be booleans
  8606. asCDataType to;
  8607. to.SetTokenType(ttBool);
  8608. // Do the actual conversion
  8609. asCArray<int> reservedVars;
  8610. rctx->bc.GetVarsUsed(reservedVars);
  8611. lctx->bc.GetVarsUsed(reservedVars);
  8612. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8613. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8614. // Verify that the conversion was successful
  8615. if( !lctx->type.dataType.IsBooleanType() )
  8616. {
  8617. asCString str;
  8618. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  8619. Error(str.AddressOf(), node);
  8620. // Force the conversion to allow compilation to proceed
  8621. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8622. }
  8623. if( !rctx->type.dataType.IsBooleanType() )
  8624. {
  8625. asCString str;
  8626. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  8627. Error(str.AddressOf(), node);
  8628. // Force the conversion to allow compilation to proceed
  8629. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8630. }
  8631. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8632. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  8633. // What kind of operator is it?
  8634. int op = node->tokenType;
  8635. if( op == ttXor )
  8636. {
  8637. if( !isConstant )
  8638. {
  8639. // Must convert to temporary variable, because we are changing the value before comparison
  8640. ConvertToTempVariableNotIn(lctx, rctx);
  8641. ConvertToTempVariableNotIn(rctx, lctx);
  8642. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8643. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8644. // Make sure they are equal if not false
  8645. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8646. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8647. MergeExprBytecode(ctx, lctx);
  8648. MergeExprBytecode(ctx, rctx);
  8649. ProcessDeferredParams(ctx);
  8650. int a = AllocateVariable(ctx->type.dataType, true);
  8651. int b = lctx->type.stackOffset;
  8652. int c = rctx->type.stackOffset;
  8653. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  8654. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8655. }
  8656. else
  8657. {
  8658. // Make sure they are equal if not false
  8659. #if AS_SIZEOF_BOOL == 1
  8660. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8661. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8662. asBYTE v = 0;
  8663. v = lctx->type.byteValue - rctx->type.byteValue;
  8664. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8665. ctx->type.isConstant = true;
  8666. ctx->type.byteValue = v;
  8667. #else
  8668. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8669. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8670. asDWORD v = 0;
  8671. v = lctx->type.intValue - rctx->type.intValue;
  8672. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8673. ctx->type.isConstant = true;
  8674. ctx->type.dwordValue = v;
  8675. #endif
  8676. }
  8677. }
  8678. else if( op == ttAnd ||
  8679. op == ttOr )
  8680. {
  8681. if( !isConstant )
  8682. {
  8683. // If or-operator and first value is 1 the second value shouldn't be calculated
  8684. // if and-operator and first value is 0 the second value shouldn't be calculated
  8685. ConvertToVariable(lctx);
  8686. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8687. MergeExprBytecode(ctx, lctx);
  8688. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  8689. int label1 = nextLabel++;
  8690. int label2 = nextLabel++;
  8691. if( op == ttAnd )
  8692. {
  8693. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  8694. ctx->bc.Instr(asBC_ClrHi);
  8695. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  8696. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  8697. ctx->bc.InstrINT(asBC_JMP, label2);
  8698. }
  8699. else if( op == ttOr )
  8700. {
  8701. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  8702. ctx->bc.Instr(asBC_ClrHi);
  8703. ctx->bc.InstrDWORD(asBC_JZ, label1);
  8704. #if AS_SIZEOF_BOOL == 1
  8705. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  8706. #else
  8707. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  8708. #endif
  8709. ctx->bc.InstrINT(asBC_JMP, label2);
  8710. }
  8711. ctx->bc.Label((short)label1);
  8712. ConvertToVariable(rctx);
  8713. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8714. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  8715. MergeExprBytecode(ctx, rctx);
  8716. ctx->bc.Label((short)label2);
  8717. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  8718. }
  8719. else
  8720. {
  8721. #if AS_SIZEOF_BOOL == 1
  8722. asBYTE v = 0;
  8723. if( op == ttAnd )
  8724. v = lctx->type.byteValue && rctx->type.byteValue;
  8725. else if( op == ttOr )
  8726. v = lctx->type.byteValue || rctx->type.byteValue;
  8727. // Remember the result
  8728. ctx->type.isConstant = true;
  8729. ctx->type.byteValue = v;
  8730. #else
  8731. asDWORD v = 0;
  8732. if( op == ttAnd )
  8733. v = lctx->type.dwordValue && rctx->type.dwordValue;
  8734. else if( op == ttOr )
  8735. v = lctx->type.dwordValue || rctx->type.dwordValue;
  8736. // Remember the result
  8737. ctx->type.isConstant = true;
  8738. ctx->type.dwordValue = v;
  8739. #endif
  8740. }
  8741. }
  8742. }
  8743. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8744. {
  8745. // Process the property accessor as get
  8746. ProcessPropertyGetAccessor(lctx, node);
  8747. ProcessPropertyGetAccessor(rctx, node);
  8748. // Make sure lctx doesn't end up with a variable used in rctx
  8749. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  8750. {
  8751. asCArray<int> vars;
  8752. rctx->bc.GetVarsUsed(vars);
  8753. int offset = AllocateVariable(lctx->type.dataType, true);
  8754. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  8755. ReleaseTemporaryVariable(offset, 0);
  8756. }
  8757. // Warn if not both operands are explicit handles
  8758. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  8759. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  8760. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  8761. {
  8762. Warning(TXT_HANDLE_COMPARISON, node);
  8763. }
  8764. // Implicitly convert null to the other type
  8765. asCDataType to;
  8766. if( lctx->type.IsNullConstant() )
  8767. to = rctx->type.dataType;
  8768. else if( rctx->type.IsNullConstant() )
  8769. to = lctx->type.dataType;
  8770. else
  8771. {
  8772. // TODO: Use the common base type
  8773. to = lctx->type.dataType;
  8774. }
  8775. // Need to pop the value if it is a null constant
  8776. if( lctx->type.IsNullConstant() )
  8777. lctx->bc.Pop(AS_PTR_SIZE);
  8778. if( rctx->type.IsNullConstant() )
  8779. rctx->bc.Pop(AS_PTR_SIZE);
  8780. // Convert both sides to explicit handles
  8781. to.MakeHandle(true);
  8782. to.MakeReference(false);
  8783. // Do the conversion
  8784. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  8785. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8786. // Both operands must be of the same type
  8787. // Verify that the conversion was successful
  8788. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8789. {
  8790. asCString str;
  8791. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8792. Error(str.AddressOf(), node);
  8793. }
  8794. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8795. {
  8796. asCString str;
  8797. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8798. Error(str.AddressOf(), node);
  8799. }
  8800. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  8801. int op = node->tokenType;
  8802. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  8803. {
  8804. // If the object handle already is in a variable we must manually pop it from the stack
  8805. if( lctx->type.isVariable )
  8806. lctx->bc.Pop(AS_PTR_SIZE);
  8807. if( rctx->type.isVariable )
  8808. rctx->bc.Pop(AS_PTR_SIZE);
  8809. // TODO: optimize: Treat the object handles as two integers, i.e. don't do REFCPY
  8810. ConvertToVariableNotIn(lctx, rctx);
  8811. ConvertToVariable(rctx);
  8812. MergeExprBytecode(ctx, lctx);
  8813. MergeExprBytecode(ctx, rctx);
  8814. int a = AllocateVariable(ctx->type.dataType, true);
  8815. int b = lctx->type.stackOffset;
  8816. int c = rctx->type.stackOffset;
  8817. // TODO: When saving the bytecode we must be able to determine that this is
  8818. // a comparison with a pointer, so that the instruction can be adapted
  8819. // to the pointer size on the platform that will execute it.
  8820. #ifdef AS_64BIT_PTR
  8821. ctx->bc.InstrW_W(asBC_CMPi64, b, c);
  8822. #else
  8823. ctx->bc.InstrW_W(asBC_CMPi, b, c);
  8824. #endif
  8825. if( op == ttEqual || op == ttIs )
  8826. ctx->bc.Instr(asBC_TZ);
  8827. else if( op == ttNotEqual || op == ttNotIs )
  8828. ctx->bc.Instr(asBC_TNZ);
  8829. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8830. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8831. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  8832. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  8833. ProcessDeferredParams(ctx);
  8834. }
  8835. else
  8836. {
  8837. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8838. Error(TXT_ILLEGAL_OPERATION, node);
  8839. }
  8840. }
  8841. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  8842. {
  8843. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  8844. // Check if the function is private
  8845. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  8846. {
  8847. asCString msg;
  8848. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  8849. Error(msg.AddressOf(), ctx->exprNode);
  8850. }
  8851. int argSize = descr->GetSpaceNeededForArguments();
  8852. if( descr->objectType && descr->returnType.IsReference() &&
  8853. !ctx->type.isVariable && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  8854. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) )
  8855. {
  8856. // The class method we're calling is returning a reference, which may be to a member of the object.
  8857. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  8858. // TODO: optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  8859. int tempRef = AllocateVariable(ctx->type.dataType, true);
  8860. ctx->bc.InstrSHORT(asBC_PSF, tempRef);
  8861. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  8862. // Add the release of this reference, as a deferred expression
  8863. asSDeferredParam deferred;
  8864. deferred.origExpr = 0;
  8865. deferred.argInOutFlags = asTM_INREF;
  8866. deferred.argNode = 0;
  8867. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  8868. ctx->deferredParams.PushLast(deferred);
  8869. }
  8870. ctx->type.Set(descr->returnType);
  8871. if( isConstructor )
  8872. {
  8873. // Sometimes the value types are allocated on the heap,
  8874. // which is when this way of constructing them is used.
  8875. asASSERT(useVariable == false);
  8876. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  8877. // The instruction has already moved the returned object to the variable
  8878. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  8879. // Clean up arguments
  8880. if( args )
  8881. AfterFunctionCall(funcId, *args, ctx, false);
  8882. ProcessDeferredParams(ctx);
  8883. return;
  8884. }
  8885. else if( descr->funcType == asFUNC_IMPORTED )
  8886. ctx->bc.Call(asBC_CALLBND , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8887. // TODO: Maybe we need two different byte codes
  8888. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  8889. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8890. else if( descr->funcType == asFUNC_SCRIPT )
  8891. ctx->bc.Call(asBC_CALL , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8892. else if( descr->funcType == asFUNC_SYSTEM )
  8893. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8894. else if( descr->funcType == asFUNC_FUNCDEF )
  8895. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  8896. if( ctx->type.dataType.IsObject() && !descr->returnType.IsReference() )
  8897. {
  8898. int returnOffset = 0;
  8899. if( useVariable )
  8900. {
  8901. // Use the given variable
  8902. returnOffset = varOffset;
  8903. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  8904. }
  8905. else
  8906. {
  8907. // Allocate a temporary variable for the returned object
  8908. // The returned object will actually be allocated on the heap, so
  8909. // we must force the allocation of the variable to do the same
  8910. returnOffset = AllocateVariable(descr->returnType, true, true);
  8911. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  8912. }
  8913. ctx->type.dataType.MakeReference(true);
  8914. // Move the pointer from the object register to the temporary variable
  8915. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  8916. // Clean up arguments
  8917. if( args )
  8918. AfterFunctionCall(funcId, *args, ctx, false);
  8919. ProcessDeferredParams(ctx);
  8920. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  8921. }
  8922. else if( descr->returnType.IsReference() )
  8923. {
  8924. asASSERT(useVariable == false);
  8925. // We cannot clean up the arguments yet, because the
  8926. // reference might be pointing to one of them.
  8927. // Clean up arguments
  8928. if( args )
  8929. AfterFunctionCall(funcId, *args, ctx, true);
  8930. // Do not process the output parameters yet, because it
  8931. // might invalidate the returned reference
  8932. if( descr->returnType.IsPrimitive() )
  8933. ctx->type.Set(descr->returnType);
  8934. else
  8935. {
  8936. ctx->bc.Instr(asBC_PshRPtr);
  8937. if( descr->returnType.IsObject() && !descr->returnType.IsObjectHandle() )
  8938. {
  8939. // We are getting the pointer to the object
  8940. // not a pointer to a object variable
  8941. ctx->type.dataType.MakeReference(false);
  8942. }
  8943. }
  8944. }
  8945. else
  8946. {
  8947. asASSERT(useVariable == false);
  8948. if( descr->returnType.GetSizeInMemoryBytes() )
  8949. {
  8950. // Allocate a temporary variable to hold the value, but make sure
  8951. // the temporary variable isn't used in any of the deferred arguments
  8952. asCArray<int> vars;
  8953. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  8954. {
  8955. asSExprContext *expr = (*args)[n]->origExpr;
  8956. if( expr )
  8957. expr->bc.GetVarsUsed(vars);
  8958. }
  8959. int offset = AllocateVariableNotIn(descr->returnType, true, &vars);
  8960. ctx->type.SetVariable(descr->returnType, offset, true);
  8961. // Move the value from the return register to the variable
  8962. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  8963. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  8964. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  8965. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  8966. }
  8967. else
  8968. ctx->type.Set(descr->returnType);
  8969. // Clean up arguments
  8970. if( args )
  8971. AfterFunctionCall(funcId, *args, ctx, false);
  8972. ProcessDeferredParams(ctx);
  8973. }
  8974. }
  8975. // This only merges the bytecode, but doesn't modify the type of the final context
  8976. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  8977. {
  8978. before->bc.AddCode(&after->bc);
  8979. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  8980. {
  8981. before->deferredParams.PushLast(after->deferredParams[n]);
  8982. after->deferredParams[n].origExpr = 0;
  8983. }
  8984. after->deferredParams.SetLength(0);
  8985. }
  8986. // This merges both bytecode and the type of the final context
  8987. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  8988. {
  8989. MergeExprBytecode(before, after);
  8990. before->type = after->type;
  8991. before->property_get = after->property_get;
  8992. before->property_set = after->property_set;
  8993. before->property_const = after->property_const;
  8994. before->property_handle = after->property_handle;
  8995. before->property_ref = after->property_ref;
  8996. before->property_arg = after->property_arg;
  8997. before->exprNode = after->exprNode;
  8998. after->property_arg = 0;
  8999. // Do not copy the origExpr member
  9000. }
  9001. void asCCompiler::FilterConst(asCArray<int> &funcs)
  9002. {
  9003. if( funcs.GetLength() == 0 ) return;
  9004. // This is only done for object methods
  9005. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  9006. if( desc->objectType == 0 ) return;
  9007. // Check if there are any non-const matches
  9008. asUINT n;
  9009. bool foundNonConst = false;
  9010. for( n = 0; n < funcs.GetLength(); n++ )
  9011. {
  9012. desc = builder->GetFunctionDescription(funcs[n]);
  9013. if( !desc->isReadOnly )
  9014. {
  9015. foundNonConst = true;
  9016. break;
  9017. }
  9018. }
  9019. if( foundNonConst )
  9020. {
  9021. // Remove all const methods
  9022. for( n = 0; n < funcs.GetLength(); n++ )
  9023. {
  9024. desc = builder->GetFunctionDescription(funcs[n]);
  9025. if( desc->isReadOnly )
  9026. {
  9027. if( n == funcs.GetLength() - 1 )
  9028. funcs.PopLast();
  9029. else
  9030. funcs[n] = funcs.PopLast();
  9031. n--;
  9032. }
  9033. }
  9034. }
  9035. }
  9036. END_AS_NAMESPACE