as_compiler.cpp 342 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007
  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. isCompilingDefaultArg = false;
  52. noCodeOutput = 0;
  53. }
  54. asCCompiler::~asCCompiler()
  55. {
  56. while( variables )
  57. {
  58. asCVariableScope *var = variables;
  59. variables = variables->parent;
  60. asDELETE(var,asCVariableScope);
  61. }
  62. }
  63. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  64. {
  65. this->builder = builder;
  66. this->engine = builder->engine;
  67. this->script = script;
  68. this->outFunc = outFunc;
  69. hasCompileErrors = false;
  70. m_isConstructor = false;
  71. m_isConstructorCalled = false;
  72. nextLabel = 0;
  73. breakLabels.SetLength(0);
  74. continueLabels.SetLength(0);
  75. byteCode.ClearAll();
  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. // Skip the private keyword if it is there
  165. asCScriptNode *node = func->firstChild;
  166. if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
  167. node = node->next;
  168. //----------------------------------------------
  169. // Examine return type
  170. bool isDestructor = false;
  171. asCDataType returnType;
  172. if( node->nodeType == snDataType )
  173. {
  174. returnType = builder->CreateDataTypeFromNode(node, script);
  175. returnType = builder->ModifyDataTypeFromNode(returnType, node->next, script, 0, 0);
  176. // Make sure the return type is instanciable or is void
  177. if( !returnType.CanBeInstanciated() &&
  178. returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  179. {
  180. asCString str;
  181. str.Format(TXT_DATA_TYPE_CANT_BE_s, returnType.Format().AddressOf());
  182. Error(str.AddressOf(), func->firstChild);
  183. }
  184. #ifndef AS_OLD
  185. // If the return type is a value type returned by value the address of the
  186. // location where the value will be stored is pushed on the stack before
  187. // the arguments
  188. if( outFunc->DoesReturnOnStack() )
  189. stackPos -= AS_PTR_SIZE;
  190. #endif
  191. }
  192. else
  193. {
  194. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  195. if( node->tokenType == ttBitNot )
  196. isDestructor = true;
  197. else
  198. m_isConstructor = true;
  199. }
  200. //----------------------------------------------
  201. // Declare parameters
  202. // Find first parameter
  203. while( node && node->nodeType != snParameterList )
  204. node = node->next;
  205. // Register parameters from last to first, otherwise they will be destroyed in the wrong order
  206. asCVariableScope vs(0);
  207. if( node ) node = node->firstChild;
  208. while( node )
  209. {
  210. // Get the parameter type
  211. asCDataType type = builder->CreateDataTypeFromNode(node, script);
  212. asETypeModifiers inoutFlag = asTM_NONE;
  213. type = builder->ModifyDataTypeFromNode(type, node->next, script, &inoutFlag, 0);
  214. // Is the data type allowed?
  215. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  216. (!type.IsReference() && !type.CanBeInstanciated()) )
  217. {
  218. asCString str;
  219. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  220. Error(str.AddressOf(), node);
  221. }
  222. // If the parameter has a name then declare it as variable
  223. node = node->next->next;
  224. if( node && node->nodeType == snIdentifier )
  225. {
  226. asCString name(&script->code[node->tokenPos], node->tokenLength);
  227. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  228. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  229. // Add marker for variable declaration
  230. byteCode.VarDecl((int)outFunc->variables.GetLength());
  231. outFunc->AddVariable(name, type, stackPos);
  232. node = node->next;
  233. // Skip the default arg
  234. if( node && node->nodeType == snExpression )
  235. node = node->next;
  236. }
  237. else
  238. vs.DeclareVariable("", type, stackPos, true);
  239. // Move to next parameter
  240. stackPos -= type.GetSizeOnStackDWords();
  241. }
  242. int n;
  243. for( n = (int)vs.variables.GetLength() - 1; n >= 0; n-- )
  244. {
  245. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  246. }
  247. // Is the return type allowed?
  248. if( (returnType.GetSizeOnStackDWords() == 0 && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  249. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  250. {
  251. asCString str;
  252. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  253. Error(str.AddressOf(), func);
  254. }
  255. variables->DeclareVariable("return", returnType, stackPos, true);
  256. //--------------------------------------------
  257. // Compile the statement block
  258. // We need to parse the statement block now
  259. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  260. asCParser parser(builder);
  261. int r = parser.ParseStatementBlock(script, func->lastChild);
  262. if( r < 0 ) return -1;
  263. asCScriptNode *block = parser.GetScriptNode();
  264. bool hasReturn;
  265. asCByteCode bc(engine);
  266. LineInstr(&bc, func->lastChild->tokenPos);
  267. CompileStatementBlock(block, false, &hasReturn, &bc);
  268. LineInstr(&bc, func->lastChild->tokenPos + func->lastChild->tokenLength);
  269. // Make sure there is a return in all paths (if not return type is void)
  270. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  271. {
  272. if( hasReturn == false )
  273. Error(TXT_NOT_ALL_PATHS_RETURN, func->lastChild);
  274. }
  275. //------------------------------------------------
  276. // Concatenate the bytecode
  277. // Insert a JitEntry at the start of the function for JIT compilers
  278. byteCode.InstrWORD(asBC_JitEntry, 0);
  279. // Count total variable size
  280. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  281. byteCode.Push(varSize);
  282. if( outFunc->objectType )
  283. {
  284. // Call the base class' default constructor unless called manually in the code
  285. if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
  286. {
  287. byteCode.InstrSHORT(asBC_PSF, 0);
  288. byteCode.Instr(asBC_RDSPTR);
  289. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  290. }
  291. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  292. // TODO: optimize: This is probably not necessary for constructors as no outside reference to the object is created yet
  293. byteCode.InstrSHORT(asBC_PSF, 0);
  294. byteCode.Instr(asBC_RDSPTR);
  295. byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  296. }
  297. // Add the code for the statement block
  298. byteCode.AddCode(&bc);
  299. // Deallocate all local variables
  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 variables destructors
  306. if( v->name != "return" && v->name != "return address" )
  307. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  308. DeallocateVariable(v->stackOffset);
  309. }
  310. }
  311. // This is the label that return statements jump to
  312. // in order to exit the function
  313. byteCode.Label(0);
  314. // Call destructors for function parameters
  315. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  316. {
  317. sVariable *v = variables->variables[n];
  318. if( v->stackOffset <= 0 )
  319. {
  320. // Call variable destructors here, for variables not yet destroyed
  321. if( v->name != "return" && v->name != "return address" )
  322. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  323. }
  324. // Do not deallocate parameters
  325. }
  326. // Release the object pointer again
  327. if( outFunc->objectType )
  328. {
  329. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  330. }
  331. // If there are compile errors, there is no reason to build the final code
  332. if( hasCompileErrors || builder->numErrors != buildErrors )
  333. return -1;
  334. // At this point there should be no variables allocated
  335. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  336. // Remove the variable scope
  337. RemoveVariableScope();
  338. // This POP is not necessary as the return will clean up the stack frame anyway.
  339. // The bytecode optimizer would remove this POP, however by not including it here
  340. // it is guaranteed it doesn't have to be adjusted by the asCRestore class when
  341. // a types are of a different size than originally compiled for.
  342. // byteCode.Pop(varSize);
  343. byteCode.Ret(-stackPos);
  344. FinalizeFunction();
  345. #ifdef AS_DEBUG
  346. // DEBUG: output byte code
  347. if( outFunc->objectType )
  348. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  349. else
  350. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  351. #endif
  352. return 0;
  353. }
  354. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  355. {
  356. if( !type.IsObject() )
  357. return 0;
  358. // CallCopyConstructor should not be called for object handles.
  359. asASSERT(!type.IsObjectHandle() || (type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_ASHANDLE)) );
  360. asCArray<asSExprContext*> args;
  361. args.PushLast(arg);
  362. // The reference parameter must be pushed on the stack
  363. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  364. // Since we're calling the copy constructor, we have to trust the function to not do
  365. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  366. // copies of the argument in order to guarantee safety.
  367. if( type.GetObjectType()->flags & asOBJ_REF )
  368. {
  369. asSExprContext ctx(engine);
  370. int func = 0;
  371. asSTypeBehaviour *beh = type.GetBehaviour();
  372. if( beh ) func = beh->copyfactory;
  373. if( func > 0 )
  374. {
  375. if( !isGlobalVar )
  376. {
  377. // Call factory and store the handle in the given variable
  378. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  379. // Pop the reference left by the function call
  380. ctx.bc.Pop(AS_PTR_SIZE);
  381. }
  382. else
  383. {
  384. // Call factory
  385. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  386. // Store the returned handle in the global variable
  387. ctx.bc.Instr(asBC_RDSPTR);
  388. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  389. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  390. ctx.bc.Pop(AS_PTR_SIZE);
  391. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  392. }
  393. bc->AddCode(&ctx.bc);
  394. return 0;
  395. }
  396. }
  397. else
  398. {
  399. asSTypeBehaviour *beh = type.GetBehaviour();
  400. int func = beh ? beh->copyconstruct : 0;
  401. if( func > 0 )
  402. {
  403. // Push the address where the object will be stored on the stack, before the argument
  404. // TODO: When the context is serializable this probably has to be changed, since this
  405. // pointer can remain on the stack while the context is suspended. There is no
  406. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  407. asCByteCode tmp(engine);
  408. if( isGlobalVar )
  409. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  410. else if( isObjectOnHeap )
  411. tmp.InstrSHORT(asBC_PSF, (short)offset);
  412. tmp.AddCode(bc);
  413. bc->AddCode(&tmp);
  414. // When the object is allocated on the stack the object pointer
  415. // must be pushed on the stack after the arguments
  416. if( !isObjectOnHeap )
  417. {
  418. asASSERT( !isGlobalVar );
  419. bc->InstrSHORT(asBC_PSF, (short)offset);
  420. if( derefDest )
  421. {
  422. // The variable is a reference to the real location, so we need to dereference it
  423. bc->Instr(asBC_RDSPTR);
  424. }
  425. }
  426. asSExprContext ctx(engine);
  427. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  428. bc->AddCode(&ctx.bc);
  429. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  430. // Mark the object as initialized
  431. if( !isObjectOnHeap )
  432. bc->ObjInfo(offset, asOBJ_INIT);
  433. return 0;
  434. }
  435. }
  436. // Class has no copy constructor/factory.
  437. asCString str;
  438. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  439. Error(str.AddressOf(), node);
  440. return -1;
  441. }
  442. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, bool isGlobalVar, bool deferDest)
  443. {
  444. if( !type.IsObject() ||
  445. (type.IsObjectHandle() && !(type.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  446. return 0;
  447. if( type.GetObjectType()->flags & asOBJ_REF )
  448. {
  449. asSExprContext ctx(engine);
  450. int func = 0;
  451. asSTypeBehaviour *beh = type.GetBehaviour();
  452. if( beh ) func = beh->factory;
  453. if( func > 0 )
  454. {
  455. if( !isGlobalVar )
  456. {
  457. // Call factory and store the handle in the given variable
  458. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  459. // Pop the reference left by the function call
  460. ctx.bc.Pop(AS_PTR_SIZE);
  461. }
  462. else
  463. {
  464. // Call factory
  465. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  466. // Store the returned handle in the global variable
  467. ctx.bc.Instr(asBC_RDSPTR);
  468. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  469. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  470. ctx.bc.Pop(AS_PTR_SIZE);
  471. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  472. }
  473. bc->AddCode(&ctx.bc);
  474. return 0;
  475. }
  476. }
  477. else
  478. {
  479. asSTypeBehaviour *beh = type.GetBehaviour();
  480. int func = 0;
  481. if( beh ) func = beh->construct;
  482. // Allocate and initialize with the default constructor
  483. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  484. {
  485. if( !isObjectOnHeap )
  486. {
  487. asASSERT( !isGlobalVar );
  488. // There is nothing to do if there is no function,
  489. // as the memory is already allocated on the stack
  490. if( func )
  491. {
  492. // Call the constructor as a normal function
  493. bc->InstrSHORT(asBC_PSF, (short)offset);
  494. if( deferDest )
  495. bc->Instr(asBC_RDSPTR);
  496. asSExprContext ctx(engine);
  497. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  498. bc->AddCode(&ctx.bc);
  499. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  500. // Mark the object as initialized
  501. bc->ObjInfo(offset, asOBJ_INIT);
  502. }
  503. }
  504. else
  505. {
  506. if( isGlobalVar )
  507. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  508. else
  509. bc->InstrSHORT(asBC_PSF, (short)offset);
  510. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  511. }
  512. return 0;
  513. }
  514. }
  515. // Class has no default factory/constructor.
  516. asCString str;
  517. // TODO: funcdef: asCDataType should have a GetTypeName()
  518. if( type.GetFuncDef() )
  519. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  520. else
  521. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  522. Error(str.AddressOf(), node);
  523. return -1;
  524. }
  525. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  526. {
  527. if( !type.IsReference() )
  528. {
  529. // Call destructor for the data type
  530. if( type.IsObject() )
  531. {
  532. // ASHANDLE is really a value type and shouldn't be deallocated. Just the destructor should be called
  533. if( isObjectOnHeap || (type.IsObjectHandle() && !(type.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  534. {
  535. // Free the memory
  536. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  537. }
  538. else
  539. {
  540. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  541. if( type.GetBehaviour()->destruct )
  542. {
  543. // Call the destructor as a regular function
  544. bc->InstrSHORT(asBC_PSF, (short)offset);
  545. asSExprContext ctx(engine);
  546. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  547. bc->AddCode(&ctx.bc);
  548. }
  549. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  550. // Mark the object as destroyed
  551. bc->ObjInfo(offset, asOBJ_UNINIT);
  552. }
  553. }
  554. }
  555. }
  556. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  557. {
  558. int r, c;
  559. script->ConvertPosToRowCol(pos, &r, &c);
  560. bc->Line(r, c);
  561. }
  562. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  563. {
  564. *hasReturn = false;
  565. bool isFinished = false;
  566. bool hasWarned = false;
  567. if( ownVariableScope )
  568. {
  569. bc->Block(true);
  570. AddVariableScope();
  571. }
  572. asCScriptNode *node = block->firstChild;
  573. while( node )
  574. {
  575. if( !hasWarned && (*hasReturn || isFinished) )
  576. {
  577. hasWarned = true;
  578. Warning(TXT_UNREACHABLE_CODE, node);
  579. }
  580. if( node->nodeType == snBreak || node->nodeType == snContinue )
  581. isFinished = true;
  582. asCByteCode statement(engine);
  583. if( node->nodeType == snDeclaration )
  584. CompileDeclaration(node, &statement);
  585. else
  586. CompileStatement(node, hasReturn, &statement);
  587. LineInstr(bc, node->tokenPos);
  588. bc->AddCode(&statement);
  589. if( !hasCompileErrors )
  590. asASSERT( tempVariables.GetLength() == 0 );
  591. node = node->next;
  592. }
  593. if( ownVariableScope )
  594. {
  595. // Deallocate variables in this block, in reverse order
  596. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  597. {
  598. sVariable *v = variables->variables[n];
  599. // Call variable destructors here, for variables not yet destroyed
  600. // If the block is terminated with a break, continue, or
  601. // return the variables are already destroyed
  602. if( !isFinished && !*hasReturn )
  603. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  604. // Don't deallocate function parameters
  605. if( v->stackOffset > 0 )
  606. DeallocateVariable(v->stackOffset);
  607. }
  608. RemoveVariableScope();
  609. bc->Block(false);
  610. }
  611. }
  612. // Entry
  613. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  614. {
  615. Reset(builder, script, outFunc);
  616. // Add a variable scope (even though variables can't be declared)
  617. AddVariableScope();
  618. asSExprContext ctx(engine);
  619. gvar->isPureConstant = false;
  620. // Parse the initialization nodes
  621. asCParser parser(builder);
  622. if( node )
  623. {
  624. int r = parser.ParseGlobalVarInit(script, node);
  625. if( r < 0 )
  626. return r;
  627. node = parser.GetScriptNode();
  628. }
  629. // Compile the expression
  630. if( node && node->nodeType == snArgList )
  631. {
  632. // Make sure that it is a registered type, and that it isn't a pointer
  633. if( gvar->datatype.GetObjectType() == 0 || gvar->datatype.IsObjectHandle() )
  634. {
  635. Error(TXT_MUST_BE_OBJECT, node);
  636. }
  637. else
  638. {
  639. // Compile the arguments
  640. asCArray<asSExprContext *> args;
  641. if( CompileArgumentList(node, args) >= 0 )
  642. {
  643. // Find all constructors
  644. asCArray<int> funcs;
  645. asSTypeBehaviour *beh = gvar->datatype.GetBehaviour();
  646. if( beh )
  647. {
  648. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  649. funcs = beh->factories;
  650. else
  651. funcs = beh->constructors;
  652. }
  653. asCString str = gvar->datatype.Format();
  654. MatchFunctions(funcs, args, node, str.AddressOf());
  655. if( funcs.GetLength() == 1 )
  656. {
  657. int r = asSUCCESS;
  658. // Add the default values for arguments not explicitly supplied
  659. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  660. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  661. r = CompileDefaultArgs(node, args, func);
  662. if( r == asSUCCESS )
  663. {
  664. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  665. {
  666. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  667. // Store the returned handle in the global variable
  668. ctx.bc.Instr(asBC_RDSPTR);
  669. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  670. ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
  671. ctx.bc.Pop(AS_PTR_SIZE);
  672. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  673. }
  674. else
  675. {
  676. // Push the address of the location where the variable will be stored on the stack.
  677. // This reference is safe, because the addresses of the global variables cannot change.
  678. // TODO: When serialization of the context is implemented this will probably have to change,
  679. // because this pointer may be on the stack while the context is suspended, and may
  680. // be difficult to serialize as the context doesn't know that the value represents a
  681. // pointer.
  682. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  683. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  684. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  685. PerformFunctionCall(funcs[0], &ctx, true, &args, gvar->datatype.GetObjectType());
  686. }
  687. }
  688. }
  689. }
  690. // Cleanup
  691. for( asUINT n = 0; n < args.GetLength(); n++ )
  692. if( args[n] )
  693. {
  694. asDELETE(args[n],asSExprContext);
  695. }
  696. }
  697. }
  698. else if( node && node->nodeType == snInitList )
  699. {
  700. asCTypeInfo ti;
  701. ti.Set(gvar->datatype);
  702. ti.isVariable = false;
  703. ti.isTemporary = false;
  704. ti.stackOffset = (short)gvar->index;
  705. ti.isLValue = true;
  706. CompileInitList(&ti, node, &ctx.bc);
  707. node = node->next;
  708. }
  709. else if( node )
  710. {
  711. // Compile the right hand expression
  712. asSExprContext expr(engine);
  713. int r = CompileAssignment(node, &expr); if( r < 0 ) return r;
  714. // Assign the value to the variable
  715. if( gvar->datatype.IsPrimitive() )
  716. {
  717. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  718. {
  719. ImplicitConversion(&expr, gvar->datatype, node, asIC_IMPLICIT_CONV);
  720. gvar->isPureConstant = true;
  721. gvar->constantValue = expr.type.qwordValue;
  722. }
  723. asSExprContext lctx(engine);
  724. lctx.type.Set(gvar->datatype);
  725. lctx.type.dataType.MakeReference(true);
  726. lctx.type.dataType.MakeReadOnly(false);
  727. lctx.type.isLValue = true;
  728. // If it is an enum value that is being compiled, then
  729. // we skip this, as the bytecode won't be used anyway
  730. if( !gvar->isEnumValue )
  731. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[gvar->index]->GetAddressOfValue());
  732. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  733. }
  734. else
  735. {
  736. // TODO: copy: Here we should look for the best matching constructor, instead of
  737. // just the copy constructor. Only if no appropriate constructor is
  738. // available should the assignment operator be used.
  739. if( (!gvar->datatype.IsObjectHandle() || gvar->datatype.GetObjectType()->flags & asOBJ_ASHANDLE) )
  740. {
  741. // Call the default constructor to have a valid object for the assignment
  742. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  743. }
  744. asSExprContext lexpr(engine);
  745. lexpr.type.Set(gvar->datatype);
  746. lexpr.type.dataType.MakeReference(true);
  747. lexpr.type.dataType.MakeReadOnly(false);
  748. lexpr.type.stackOffset = -1;
  749. lexpr.type.isLValue = true;
  750. if( gvar->datatype.IsObjectHandle() )
  751. lexpr.type.isExplicitHandle = true;
  752. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  753. // If left expression resolves into a registered type
  754. // check if the assignment operator is overloaded, and check
  755. // the type of the right hand expression. If none is found
  756. // the default action is a direct copy if it is the same type
  757. // and a simple assignment.
  758. bool assigned = false;
  759. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  760. {
  761. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  762. if( assigned )
  763. {
  764. // Pop the resulting value
  765. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  766. // Release the argument
  767. ProcessDeferredParams(&ctx);
  768. }
  769. }
  770. if( !assigned )
  771. {
  772. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  773. // If the expression is constant and the variable also is constant
  774. // then mark the variable as pure constant. This will allow the compiler
  775. // to optimize expressions with this variable.
  776. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  777. {
  778. gvar->isPureConstant = true;
  779. gvar->constantValue = expr.type.qwordValue;
  780. }
  781. // Add expression code to bytecode
  782. MergeExprBytecode(&ctx, &expr);
  783. // Add byte code for storing value of expression in variable
  784. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  785. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node);
  786. // Release temporary variables used by expression
  787. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  788. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  789. }
  790. }
  791. }
  792. else if( gvar->datatype.IsObject() && (!gvar->datatype.IsObjectHandle() || gvar->datatype.GetObjectType()->flags & asOBJ_ASHANDLE) )
  793. {
  794. // Call the default constructor in case no explicit initialization is given
  795. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  796. }
  797. // Concatenate the bytecode
  798. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  799. // Add information on the line number for the global variable
  800. size_t pos = 0;
  801. if( gvar->idNode )
  802. pos = gvar->idNode->tokenPos;
  803. else if( gvar->nextNode )
  804. pos = gvar->nextNode->tokenPos;
  805. LineInstr(&byteCode, pos);
  806. // We need to push zeroes on the stack to guarantee
  807. // that temporary object handles are clear
  808. int n;
  809. for( n = 0; n < varSize; n++ )
  810. byteCode.InstrINT(asBC_PshC4, 0);
  811. byteCode.AddCode(&ctx.bc);
  812. // Deallocate variables in this block, in reverse order
  813. for( n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  814. {
  815. sVariable *v = variables->variables[n];
  816. // Call variable destructors here, for variables not yet destroyed
  817. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  818. DeallocateVariable(v->stackOffset);
  819. }
  820. if( hasCompileErrors ) return -1;
  821. // At this point there should be no variables allocated
  822. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  823. // Remove the variable scope again
  824. RemoveVariableScope();
  825. byteCode.Ret(0);
  826. FinalizeFunction();
  827. #ifdef AS_DEBUG
  828. // DEBUG: output byte code
  829. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  830. #endif
  831. return 0;
  832. }
  833. void asCCompiler::FinalizeFunction()
  834. {
  835. asUINT n;
  836. // Tell the bytecode which variables are temporary
  837. for( n = 0; n < variableIsTemporary.GetLength(); n++ )
  838. {
  839. if( variableIsTemporary[n] )
  840. byteCode.DefineTemporaryVariable(GetVariableOffset(n));
  841. }
  842. // Finalize the bytecode
  843. byteCode.Finalize();
  844. byteCode.ExtractObjectVariableInfo(outFunc);
  845. // Compile the list of object variables for the exception handler
  846. for( n = 0; n < variableAllocations.GetLength(); n++ )
  847. {
  848. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  849. {
  850. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  851. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  852. outFunc->objVariableIsOnHeap.PushLast(variableIsOnHeap[n]);
  853. }
  854. }
  855. // Copy byte code to the function
  856. outFunc->byteCode.SetLength(byteCode.GetSize());
  857. byteCode.Output(outFunc->byteCode.AddressOf());
  858. outFunc->AddReferences();
  859. outFunc->stackNeeded = byteCode.largestStackUsed;
  860. outFunc->lineNumbers = byteCode.lineNumbers;
  861. }
  862. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, asCArray<int> *reservedVars, bool /* forceOnHeap */)
  863. {
  864. asCDataType param = *paramType;
  865. if( paramType->GetTokenType() == ttQuestion )
  866. {
  867. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  868. param = ctx->type.dataType;
  869. param.MakeHandle(ctx->type.isExplicitHandle);
  870. param.MakeReference(paramType->IsReference());
  871. param.MakeReadOnly(paramType->IsReadOnly());
  872. }
  873. else
  874. param = *paramType;
  875. asCDataType dt = param;
  876. // Need to protect arguments by reference
  877. if( isFunction && dt.IsReference() )
  878. {
  879. if( paramType->GetTokenType() == ttQuestion )
  880. {
  881. asCByteCode tmpBC(engine);
  882. // Place the type id on the stack as a hidden parameter
  883. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  884. // Insert the code before the expression code
  885. tmpBC.AddCode(&ctx->bc);
  886. ctx->bc.AddCode(&tmpBC);
  887. }
  888. // Allocate a temporary variable of the same type as the argument
  889. dt.MakeReference(false);
  890. dt.MakeReadOnly(false);
  891. int offset;
  892. if( refType == 1 ) // &in
  893. {
  894. ProcessPropertyGetAccessor(ctx, node);
  895. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  896. // Even if the same variable is passed in another argument as non-const then there is no problem
  897. if( dt.IsPrimitive() || dt.IsNullHandle() )
  898. {
  899. IsVariableInitialized(&ctx->type, node);
  900. if( ctx->type.dataType.IsReference() ) ConvertToVariableNotIn(ctx, reservedVars);
  901. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  902. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  903. ConvertToTempVariableNotIn(ctx, reservedVars);
  904. PushVariableOnStack(ctx, true);
  905. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  906. }
  907. else
  908. {
  909. IsVariableInitialized(&ctx->type, node);
  910. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, reservedVars);
  911. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  912. {
  913. asCString str;
  914. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  915. Error(str.AddressOf(), node);
  916. ctx->type.Set(param);
  917. }
  918. // If the argument already is a temporary
  919. // variable we don't need to allocate another
  920. // If the parameter is read-only and the object already is a local
  921. // variable then it is not necessary to make a copy either
  922. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  923. {
  924. // Make sure the variable is not used in the expression
  925. asCArray<int> vars;
  926. ctx->bc.GetVarsUsed(vars);
  927. if( reservedVars ) vars.Concatenate(*reservedVars);
  928. offset = AllocateVariableNotIn(dt, true, &vars);
  929. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  930. // Allocate and construct the temporary object
  931. asCByteCode tmpBC(engine);
  932. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  933. // Insert the code before the expression code
  934. tmpBC.AddCode(&ctx->bc);
  935. ctx->bc.AddCode(&tmpBC);
  936. // Assign the evaluated expression to the temporary variable
  937. PrepareForAssignment(&dt, ctx, node);
  938. dt.MakeReference(IsVariableOnHeap(offset));
  939. asCTypeInfo type;
  940. type.Set(dt);
  941. type.isTemporary = true;
  942. type.stackOffset = (short)offset;
  943. if( dt.IsObjectHandle() )
  944. type.isExplicitHandle = true;
  945. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  946. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  947. ctx->bc.Pop(ctx->type.dataType.GetSizeOnStackDWords());
  948. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  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. if( paramType->IsReadOnly() )
  954. ctx->type.dataType.MakeReadOnly(true);
  955. }
  956. }
  957. }
  958. else if( refType == 2 ) // &out
  959. {
  960. // Make sure the variable is not used in the expression
  961. asCArray<int> vars;
  962. ctx->bc.GetVarsUsed(vars);
  963. if( reservedVars ) vars.Concatenate(*reservedVars);
  964. offset = AllocateVariableNotIn(dt, true, &vars);
  965. if( dt.IsPrimitive() )
  966. {
  967. ctx->type.SetVariable(dt, offset, true);
  968. PushVariableOnStack(ctx, true);
  969. }
  970. else
  971. {
  972. // Allocate and construct the temporary object
  973. asCByteCode tmpBC(engine);
  974. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  975. // Insert the code before the expression code
  976. tmpBC.AddCode(&ctx->bc);
  977. ctx->bc.AddCode(&tmpBC);
  978. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  979. asCTypeInfo type;
  980. type.Set(dt);
  981. type.isTemporary = true;
  982. type.stackOffset = (short)offset;
  983. ctx->type = type;
  984. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  985. if( dt.IsObject() && !dt.IsObjectHandle() )
  986. ctx->bc.Instr(asBC_RDSPTR);
  987. }
  988. // After the function returns the temporary variable will
  989. // be assigned to the expression, if it is a valid lvalue
  990. }
  991. else if( refType == asTM_INOUTREF )
  992. {
  993. ProcessPropertyGetAccessor(ctx, node);
  994. // Literal constants cannot be passed to inout ref arguments
  995. if( !ctx->type.isVariable && ctx->type.isConstant )
  996. {
  997. Error(TXT_NOT_VALID_REFERENCE, node);
  998. }
  999. // Only objects that support object handles
  1000. // can be guaranteed to be safe. Local variables are
  1001. // already safe, so there is no need to add an extra
  1002. // references
  1003. if( !engine->ep.allowUnsafeReferences &&
  1004. !ctx->type.isVariable &&
  1005. ctx->type.dataType.IsObject() &&
  1006. !ctx->type.dataType.IsObjectHandle() &&
  1007. ctx->type.dataType.GetBehaviour()->addref &&
  1008. ctx->type.dataType.GetBehaviour()->release )
  1009. {
  1010. // Store a handle to the object as local variable
  1011. asSExprContext tmp(engine);
  1012. asCDataType dt = ctx->type.dataType;
  1013. dt.MakeHandle(true);
  1014. dt.MakeReference(false);
  1015. asCArray<int> vars;
  1016. ctx->bc.GetVarsUsed(vars);
  1017. if( reservedVars ) vars.Concatenate(*reservedVars);
  1018. offset = AllocateVariableNotIn(dt, true, &vars);
  1019. // Copy the handle
  1020. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1021. ctx->bc.Instr(asBC_RDSPTR);
  1022. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1023. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1024. ctx->bc.Pop(AS_PTR_SIZE);
  1025. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1026. dt.MakeHandle(false);
  1027. dt.MakeReference(true);
  1028. // Release previous temporary variable stored in the context (if any)
  1029. if( ctx->type.isTemporary )
  1030. {
  1031. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1032. }
  1033. ctx->type.SetVariable(dt, offset, true);
  1034. }
  1035. // Make sure the reference to the value is on the stack
  1036. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() )
  1037. Dereference(ctx, true);
  1038. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1039. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1040. else if( ctx->type.dataType.IsPrimitive() )
  1041. ctx->bc.Instr(asBC_PshRPtr);
  1042. }
  1043. }
  1044. else
  1045. {
  1046. ProcessPropertyGetAccessor(ctx, node);
  1047. if( dt.IsPrimitive() )
  1048. {
  1049. IsVariableInitialized(&ctx->type, node);
  1050. if( ctx->type.dataType.IsReference() ) ConvertToVariableNotIn(ctx, reservedVars);
  1051. // Implicitly convert primitives to the parameter type
  1052. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1053. if( ctx->type.isVariable )
  1054. {
  1055. PushVariableOnStack(ctx, dt.IsReference());
  1056. }
  1057. else if( ctx->type.isConstant )
  1058. {
  1059. ConvertToVariableNotIn(ctx, reservedVars);
  1060. PushVariableOnStack(ctx, dt.IsReference());
  1061. }
  1062. }
  1063. else
  1064. {
  1065. IsVariableInitialized(&ctx->type, node);
  1066. // Implicitly convert primitives to the parameter type
  1067. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1068. // Was the conversion successful?
  1069. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1070. {
  1071. asCString str;
  1072. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1073. Error(str.AddressOf(), node);
  1074. ctx->type.Set(dt);
  1075. }
  1076. if( dt.IsObjectHandle() )
  1077. ctx->type.isExplicitHandle = true;
  1078. if( dt.IsObject() )
  1079. {
  1080. if( !dt.IsReference() )
  1081. {
  1082. // Objects passed by value must be placed in temporary variables
  1083. // so that they are guaranteed to not be referenced anywhere else.
  1084. // The object must also be allocated on the heap, as the memory will
  1085. // be deleted by in as_callfunc_xxx.
  1086. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1087. PrepareTemporaryObject(node, ctx, reservedVars, true);
  1088. // The implicit conversion shouldn't convert the object to
  1089. // non-reference yet. It will be dereferenced just before the call.
  1090. // Otherwise the object might be missed by the exception handler.
  1091. dt.MakeReference(true);
  1092. }
  1093. else
  1094. {
  1095. // An object passed by reference should place the pointer to
  1096. // the object on the stack.
  1097. dt.MakeReference(false);
  1098. }
  1099. }
  1100. }
  1101. }
  1102. // Don't put any pointer on the stack yet
  1103. if( param.IsReference() || param.IsObject() )
  1104. {
  1105. // &inout parameter may leave the reference on the stack already
  1106. if( refType != 3 )
  1107. {
  1108. ctx->bc.Pop(AS_PTR_SIZE);
  1109. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1110. }
  1111. ProcessDeferredParams(ctx);
  1112. }
  1113. }
  1114. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1115. {
  1116. // When a match has been found, compile the final byte code using correct parameter types
  1117. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1118. // Add code for arguments
  1119. asSExprContext e(engine);
  1120. int n;
  1121. for( n = (int)args.GetLength()-1; n >= 0; n-- )
  1122. {
  1123. // Make sure PrepareArgument doesn't use any variable that is already
  1124. // being used by any of the following argument expressions
  1125. asCArray<int> reservedVars;
  1126. for( int m = n-1; m >= 0; m-- )
  1127. args[m]->bc.GetVarsUsed(reservedVars);
  1128. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], &reservedVars);
  1129. }
  1130. bc->AddCode(&e.bc);
  1131. }
  1132. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1133. {
  1134. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1135. int offset = 0;
  1136. if( addOneToOffset )
  1137. offset += AS_PTR_SIZE;
  1138. #ifndef AS_OLD
  1139. // The address of where the return value should be stored is push on top of the arguments
  1140. if( descr->DoesReturnOnStack() )
  1141. offset += AS_PTR_SIZE;
  1142. #endif
  1143. // Move the objects that are sent by value to the stack just before the call
  1144. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1145. {
  1146. if( descr->parameterTypes[n].IsReference() )
  1147. {
  1148. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1149. {
  1150. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1151. {
  1152. if( (args[n]->type.isVariable || args[n]->type.isTemporary) &&
  1153. !IsVariableOnHeap(args[n]->type.stackOffset) )
  1154. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1155. // as the value allocated on the stack is guaranteed to be safe
  1156. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1157. else
  1158. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1159. }
  1160. if( args[n]->type.dataType.IsObjectHandle() )
  1161. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1162. }
  1163. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1164. {
  1165. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1166. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1167. {
  1168. // Send the object as a reference to the object,
  1169. // and not to the variable holding the object
  1170. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1171. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1172. // as the value allocated on the stack is guaranteed to be safe
  1173. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1174. else
  1175. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1176. }
  1177. else
  1178. {
  1179. if( args[n]->type.dataType.GetObjectType() &&
  1180. (args[n]->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) &&
  1181. args[n]->type.isVariable &&
  1182. IsVariableOnHeap(args[n]->type.stackOffset) )
  1183. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1184. else
  1185. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1186. }
  1187. }
  1188. }
  1189. else if( descr->parameterTypes[n].IsObject() )
  1190. {
  1191. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1192. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1193. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1194. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1195. // The temporary variable must not be freed as it will no longer hold an object
  1196. DeallocateVariable(args[n]->type.stackOffset);
  1197. args[n]->type.isTemporary = false;
  1198. }
  1199. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1200. }
  1201. }
  1202. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1203. {
  1204. asASSERT(node->nodeType == snArgList);
  1205. // Count arguments
  1206. asCScriptNode *arg = node->firstChild;
  1207. int argCount = 0;
  1208. while( arg )
  1209. {
  1210. argCount++;
  1211. arg = arg->next;
  1212. }
  1213. // Prepare the arrays
  1214. args.SetLength(argCount);
  1215. int n;
  1216. for( n = 0; n < argCount; n++ )
  1217. args[n] = 0;
  1218. n = argCount-1;
  1219. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1220. bool anyErrors = false;
  1221. arg = node->lastChild;
  1222. while( arg )
  1223. {
  1224. asSExprContext expr(engine);
  1225. int r = CompileAssignment(arg, &expr);
  1226. if( r < 0 ) anyErrors = true;
  1227. args[n] = asNEW(asSExprContext)(engine);
  1228. MergeExprBytecodeAndType(args[n], &expr);
  1229. n--;
  1230. arg = arg->prev;
  1231. }
  1232. return anyErrors ? -1 : 0;
  1233. }
  1234. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1235. {
  1236. bool anyErrors = false;
  1237. asCArray<int> varsUsed;
  1238. int explicitArgs = (int)args.GetLength();
  1239. for( int p = 0; p < explicitArgs; p++ )
  1240. args[p]->bc.GetVarsUsed(varsUsed);
  1241. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1242. args.SetLength(func->parameterTypes.GetLength());
  1243. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1244. args[c] = 0;
  1245. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1246. {
  1247. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1248. // Parse the default arg string
  1249. asCParser parser(builder);
  1250. asCScriptCode code;
  1251. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1252. int r = parser.ParseExpression(&code);
  1253. if( r < 0 ) { anyErrors = true; continue; }
  1254. asCScriptNode *arg = parser.GetScriptNode();
  1255. // Temporarily set the script code to the default arg expression
  1256. asCScriptCode *origScript = script;
  1257. script = &code;
  1258. // Don't allow the expression to access local variables
  1259. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function
  1260. isCompilingDefaultArg = true;
  1261. asSExprContext expr(engine);
  1262. r = CompileExpression(arg, &expr);
  1263. isCompilingDefaultArg = false;
  1264. script = origScript;
  1265. if( r < 0 )
  1266. {
  1267. asCString msg;
  1268. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1269. Error(msg.AddressOf(), node);
  1270. anyErrors = true;
  1271. continue;
  1272. }
  1273. args[n] = asNEW(asSExprContext)(engine);
  1274. MergeExprBytecodeAndType(args[n], &expr);
  1275. // Make sure the default arg expression doesn't end up
  1276. // with a variable that is used in a previous expression
  1277. if( args[n]->type.isVariable )
  1278. {
  1279. int offset = args[n]->type.stackOffset;
  1280. if( varsUsed.Exists(offset) )
  1281. {
  1282. // Release the current temporary variable
  1283. ReleaseTemporaryVariable(args[n]->type, 0);
  1284. asCDataType dt = args[n]->type.dataType;
  1285. dt.MakeReference(false);
  1286. int newOffset = AllocateVariableNotIn(dt, true, &varsUsed, IsVariableOnHeap(offset));
  1287. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1288. args[n]->bc.ExchangeVar(offset, newOffset);
  1289. args[n]->type.stackOffset = (short)newOffset;
  1290. args[n]->type.isTemporary = true;
  1291. args[n]->type.isVariable = true;
  1292. }
  1293. }
  1294. }
  1295. return anyErrors ? -1 : 0;
  1296. }
  1297. 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)
  1298. {
  1299. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1300. asUINT n;
  1301. if( funcs.GetLength() > 0 )
  1302. {
  1303. // Check the number of parameters in the found functions
  1304. for( n = 0; n < funcs.GetLength(); ++n )
  1305. {
  1306. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1307. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1308. {
  1309. bool noMatch = true;
  1310. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1311. {
  1312. // Count the number of default args
  1313. asUINT defaultArgs = 0;
  1314. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1315. if( desc->defaultArgs[d] )
  1316. defaultArgs++;
  1317. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1318. noMatch = false;
  1319. }
  1320. if( noMatch )
  1321. {
  1322. // remove it from the list
  1323. if( n == funcs.GetLength()-1 )
  1324. funcs.PopLast();
  1325. else
  1326. funcs[n] = funcs.PopLast();
  1327. n--;
  1328. }
  1329. }
  1330. }
  1331. // Match functions with the parameters, and discard those that do not match
  1332. asCArray<int> matchingFuncs = funcs;
  1333. for( n = 0; n < args.GetLength(); ++n )
  1334. {
  1335. asCArray<int> tempFuncs;
  1336. MatchArgument(funcs, tempFuncs, &args[n]->type, n, allowObjectConstruct);
  1337. // Intersect the found functions with the list of matching functions
  1338. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1339. {
  1340. asUINT c;
  1341. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1342. {
  1343. if( matchingFuncs[f] == tempFuncs[c] )
  1344. break;
  1345. }
  1346. // Was the function a match?
  1347. if( c == tempFuncs.GetLength() )
  1348. {
  1349. // No, remove it from the list
  1350. if( f == matchingFuncs.GetLength()-1 )
  1351. matchingFuncs.PopLast();
  1352. else
  1353. matchingFuncs[f] = matchingFuncs.PopLast();
  1354. f--;
  1355. }
  1356. }
  1357. }
  1358. funcs = matchingFuncs;
  1359. }
  1360. if( !isConstMethod )
  1361. FilterConst(funcs);
  1362. if( funcs.GetLength() != 1 && !silent )
  1363. {
  1364. // Build a readable string of the function with parameter types
  1365. asCString str;
  1366. if( scope != "" )
  1367. {
  1368. if( scope == "::" )
  1369. str = scope;
  1370. else
  1371. str = scope + "::";
  1372. }
  1373. str += name;
  1374. str += "(";
  1375. if( args.GetLength() )
  1376. str += args[0]->type.dataType.Format();
  1377. for( n = 1; n < args.GetLength(); n++ )
  1378. str += ", " + args[n]->type.dataType.Format();
  1379. str += ")";
  1380. if( isConstMethod )
  1381. str += " const";
  1382. if( objectType && scope == "" )
  1383. str = objectType->name + "::" + str;
  1384. if( funcs.GetLength() == 0 )
  1385. {
  1386. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1387. Error(str.AddressOf(), node);
  1388. // Print the list of candidates
  1389. if( origFuncs.GetLength() > 0 )
  1390. {
  1391. int r = 0, c = 0;
  1392. asASSERT( node );
  1393. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1394. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1395. PrintMatchingFuncs(origFuncs, node);
  1396. }
  1397. }
  1398. else
  1399. {
  1400. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1401. Error(str.AddressOf(), node);
  1402. PrintMatchingFuncs(funcs, node);
  1403. }
  1404. }
  1405. }
  1406. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1407. {
  1408. // Get the data type
  1409. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script);
  1410. // Declare all variables in this declaration
  1411. asCScriptNode *node = decl->firstChild->next;
  1412. while( node )
  1413. {
  1414. // Is the type allowed?
  1415. if( !type.CanBeInstanciated() )
  1416. {
  1417. asCString str;
  1418. // TODO: Change to "'type' cannot be declared as variable"
  1419. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1420. Error(str.AddressOf(), node);
  1421. // Use int instead to avoid further problems
  1422. type = asCDataType::CreatePrimitive(ttInt, false);
  1423. }
  1424. // A shared object may not declare variables of non-shared types
  1425. if( outFunc->objectType && outFunc->objectType->IsShared() )
  1426. {
  1427. asCObjectType *ot = type.GetObjectType();
  1428. if( ot && !ot->IsShared() )
  1429. {
  1430. asCString msg;
  1431. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1432. Error(msg.AddressOf(), decl);
  1433. }
  1434. }
  1435. // Get the name of the identifier
  1436. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1437. // Verify that the name isn't used by a dynamic data type
  1438. if( engine->GetObjectType(name.AddressOf()) != 0 )
  1439. {
  1440. asCString str;
  1441. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1442. Error(str.AddressOf(), node);
  1443. }
  1444. int offset = AllocateVariable(type, false);
  1445. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1446. {
  1447. asCString str;
  1448. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1449. Error(str.AddressOf(), node);
  1450. // Don't continue after this error, as it will just
  1451. // lead to more errors that are likely false
  1452. return;
  1453. }
  1454. // Add marker that the variable has been declared
  1455. bc->VarDecl((int)outFunc->variables.GetLength());
  1456. outFunc->AddVariable(name, type, offset);
  1457. // Keep the node for the variable decl
  1458. asCScriptNode *varNode = node;
  1459. node = node->next;
  1460. if( node && node->nodeType == snArgList )
  1461. {
  1462. // Make sure that it is a registered type, and that is isn't a pointer
  1463. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1464. {
  1465. Error(TXT_MUST_BE_OBJECT, node);
  1466. }
  1467. else
  1468. {
  1469. // Compile the arguments
  1470. asCArray<asSExprContext *> args;
  1471. if( CompileArgumentList(node, args) >= 0 )
  1472. {
  1473. // Find all constructors
  1474. asCArray<int> funcs;
  1475. asSTypeBehaviour *beh = type.GetBehaviour();
  1476. if( beh )
  1477. {
  1478. if( type.GetObjectType()->flags & asOBJ_REF )
  1479. funcs = beh->factories;
  1480. else
  1481. funcs = beh->constructors;
  1482. }
  1483. asCString str = type.Format();
  1484. MatchFunctions(funcs, args, node, str.AddressOf());
  1485. if( funcs.GetLength() == 1 )
  1486. {
  1487. int r = asSUCCESS;
  1488. // Add the default values for arguments not explicitly supplied
  1489. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1490. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1491. r = CompileDefaultArgs(node, args, func);
  1492. if( r == asSUCCESS )
  1493. {
  1494. sVariable *v = variables->GetVariable(name.AddressOf());
  1495. asSExprContext ctx(engine);
  1496. if( v->type.GetObjectType() && (v->type.GetObjectType()->flags & asOBJ_REF) )
  1497. {
  1498. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
  1499. // Pop the reference left by the function call
  1500. ctx.bc.Pop(AS_PTR_SIZE);
  1501. }
  1502. else
  1503. {
  1504. // When the object is allocated on the heap, the address where the
  1505. // reference will be stored must be pushed on the stack before the
  1506. // arguments. This reference on the stack is safe, even if the script
  1507. // is suspended during the evaluation of the arguments.
  1508. if( v->onHeap )
  1509. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1510. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1511. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1512. // When the object is allocated on the stack, the address to the
  1513. // object is pushed on the stack after the arguments as the object pointer
  1514. if( !v->onHeap )
  1515. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1516. PerformFunctionCall(funcs[0], &ctx, v->onHeap, &args, type.GetObjectType());
  1517. // TODO: value on stack: This probably has to be done in PerformFunctionCall
  1518. // Mark the object as initialized
  1519. ctx.bc.ObjInfo(v->stackOffset, asOBJ_INIT);
  1520. }
  1521. bc->AddCode(&ctx.bc);
  1522. }
  1523. }
  1524. }
  1525. // Cleanup
  1526. for( asUINT n = 0; n < args.GetLength(); n++ )
  1527. if( args[n] )
  1528. {
  1529. asDELETE(args[n],asSExprContext);
  1530. }
  1531. }
  1532. node = node->next;
  1533. }
  1534. else if( node && node->nodeType == snInitList )
  1535. {
  1536. sVariable *v = variables->GetVariable(name.AddressOf());
  1537. asCTypeInfo ti;
  1538. ti.Set(type);
  1539. ti.isVariable = true;
  1540. ti.isTemporary = false;
  1541. ti.stackOffset = (short)v->stackOffset;
  1542. ti.isLValue = true;
  1543. CompileInitList(&ti, node, bc);
  1544. node = node->next;
  1545. }
  1546. else if( node && node->nodeType == snAssignment )
  1547. {
  1548. asSExprContext ctx(engine);
  1549. // TODO: copy: Here we should look for the best matching constructor, instead of
  1550. // just the copy constructor. Only if no appropriate constructor is
  1551. // available should the assignment operator be used.
  1552. // Call the default constructor here
  1553. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, varNode);
  1554. // Compile the expression
  1555. asSExprContext expr(engine);
  1556. int r = CompileAssignment(node, &expr);
  1557. if( r >= 0 )
  1558. {
  1559. if( type.IsPrimitive() )
  1560. {
  1561. if( type.IsReadOnly() && expr.type.isConstant )
  1562. {
  1563. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1564. sVariable *v = variables->GetVariable(name.AddressOf());
  1565. v->isPureConstant = true;
  1566. v->constantValue = expr.type.qwordValue;
  1567. }
  1568. asSExprContext lctx(engine);
  1569. lctx.type.SetVariable(type, offset, false);
  1570. lctx.type.dataType.MakeReadOnly(false);
  1571. lctx.type.isLValue = true;
  1572. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1573. ProcessDeferredParams(&ctx);
  1574. }
  1575. else
  1576. {
  1577. // TODO: We can use a copy constructor here
  1578. sVariable *v = variables->GetVariable(name.AddressOf());
  1579. asSExprContext lexpr(engine);
  1580. lexpr.type.Set(type);
  1581. lexpr.type.dataType.MakeReference(v->onHeap);
  1582. // Allow initialization of constant variables
  1583. lexpr.type.dataType.MakeReadOnly(false);
  1584. if( type.IsObjectHandle() )
  1585. lexpr.type.isExplicitHandle = true;
  1586. lexpr.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1587. lexpr.type.stackOffset = (short)v->stackOffset;
  1588. lexpr.type.isVariable = true;
  1589. lexpr.type.isLValue = true;
  1590. // If left expression resolves into a registered type
  1591. // check if the assignment operator is overloaded, and check
  1592. // the type of the right hand expression. If none is found
  1593. // the default action is a direct copy if it is the same type
  1594. // and a simple assignment.
  1595. bool assigned = false;
  1596. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1597. {
  1598. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1599. if( assigned )
  1600. {
  1601. // Pop the resulting value
  1602. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  1603. // Release the argument
  1604. ProcessDeferredParams(&ctx);
  1605. // Release temporary variable that may be allocated by the overloaded operator
  1606. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1607. }
  1608. }
  1609. if( !assigned )
  1610. {
  1611. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  1612. // If the expression is constant and the variable also is constant
  1613. // then mark the variable as pure constant. This will allow the compiler
  1614. // to optimize expressions with this variable.
  1615. if( v->type.IsReadOnly() && expr.type.isConstant )
  1616. {
  1617. v->isPureConstant = true;
  1618. v->constantValue = expr.type.qwordValue;
  1619. }
  1620. // Add expression code to bytecode
  1621. MergeExprBytecode(&ctx, &expr);
  1622. // Add byte code for storing value of expression in variable
  1623. ctx.bc.AddCode(&lexpr.bc);
  1624. lexpr.type.stackOffset = (short)v->stackOffset;
  1625. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node->prev);
  1626. // Release temporary variables used by expression
  1627. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  1628. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  1629. ProcessDeferredParams(&ctx);
  1630. }
  1631. }
  1632. }
  1633. node = node->next;
  1634. bc->AddCode(&ctx.bc);
  1635. // TODO: Can't this leave deferred output params without being compiled?
  1636. }
  1637. else
  1638. {
  1639. // Call the default constructor here if no explicit initialization is done
  1640. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, varNode);
  1641. }
  1642. }
  1643. }
  1644. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc)
  1645. {
  1646. // Check if the type supports initialization lists
  1647. if( var->dataType.GetObjectType() == 0 ||
  1648. var->dataType.GetBehaviour()->listFactory == 0 ||
  1649. var->dataType.IsObjectHandle() )
  1650. {
  1651. asCString str;
  1652. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  1653. Error(str.AddressOf(), node);
  1654. return;
  1655. }
  1656. // Count the number of elements and initialize the array with the correct size
  1657. int countElements = 0;
  1658. asCScriptNode *el = node->firstChild;
  1659. while( el )
  1660. {
  1661. countElements++;
  1662. el = el->next;
  1663. }
  1664. // Construct the array with the size elements
  1665. // TODO: value on stack: This needs to support value types on the stack as well
  1666. // Find the list factory
  1667. // TODO: initlist: Add support for value types as well
  1668. int funcId = var->dataType.GetBehaviour()->listFactory;
  1669. asCArray<asSExprContext *> args;
  1670. asSExprContext arg1(engine);
  1671. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  1672. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  1673. args.PushLast(&arg1);
  1674. asSExprContext ctx(engine);
  1675. PrepareFunctionCall(funcId, &ctx.bc, args);
  1676. MoveArgsToStack(funcId, &ctx.bc, args, false);
  1677. if( var->isVariable )
  1678. {
  1679. // Call factory and store the handle in the given variable
  1680. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  1681. ctx.bc.Pop(AS_PTR_SIZE);
  1682. }
  1683. else
  1684. {
  1685. PerformFunctionCall(funcId, &ctx, false, &args);
  1686. // Store the returned handle in the global variable
  1687. ctx.bc.Instr(asBC_RDSPTR);
  1688. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1689. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  1690. ctx.bc.Pop(AS_PTR_SIZE);
  1691. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1692. }
  1693. bc->AddCode(&ctx.bc);
  1694. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  1695. // initialization lists with different types for different elements? Maybe
  1696. // by using the variable arguments the initialization can be done with one
  1697. // call, passing all the elements as arguments. The registered function can
  1698. // then traverse them however it wants.
  1699. // Find the indexing operator that is not read-only that will be used for all elements
  1700. asCDataType retType;
  1701. retType = var->dataType.GetSubType();
  1702. retType.MakeReference(true);
  1703. retType.MakeReadOnly(false);
  1704. funcId = 0;
  1705. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  1706. {
  1707. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  1708. if( !desc->isReadOnly &&
  1709. desc->parameterTypes.GetLength() == 1 &&
  1710. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1711. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1712. desc->returnType == retType &&
  1713. desc->name == "opIndex" )
  1714. {
  1715. funcId = var->dataType.GetObjectType()->methods[n];
  1716. break;
  1717. }
  1718. }
  1719. if( funcId == 0 )
  1720. {
  1721. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  1722. return;
  1723. }
  1724. asUINT index = 0;
  1725. el = node->firstChild;
  1726. while( el )
  1727. {
  1728. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  1729. {
  1730. asSExprContext lctx(engine);
  1731. asSExprContext rctx(engine);
  1732. if( el->nodeType == snAssignment )
  1733. {
  1734. // Compile the assignment expression
  1735. CompileAssignment(el, &rctx);
  1736. }
  1737. else if( el->nodeType == snInitList )
  1738. {
  1739. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  1740. rctx.type.Set(var->dataType.GetSubType());
  1741. rctx.type.isVariable = true;
  1742. rctx.type.isTemporary = true;
  1743. rctx.type.stackOffset = (short)offset;
  1744. CompileInitList(&rctx.type, el, &rctx.bc);
  1745. // Put the object on the stack
  1746. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  1747. // It is a reference that we place on the stack
  1748. rctx.type.dataType.MakeReference(true);
  1749. }
  1750. // Compile the lvalue
  1751. lctx.bc.InstrDWORD(asBC_PshC4, index);
  1752. if( var->isVariable )
  1753. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  1754. else
  1755. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1756. lctx.bc.Instr(asBC_RDSPTR);
  1757. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  1758. if( !var->dataType.GetSubType().IsPrimitive() )
  1759. lctx.bc.Instr(asBC_PshRPtr);
  1760. lctx.type.Set(var->dataType.GetSubType());
  1761. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  1762. lctx.type.dataType.MakeReference(true);
  1763. // If the element type is handles, then we're expected to do handle assignments
  1764. if( lctx.type.dataType.IsObjectHandle() )
  1765. lctx.type.isExplicitHandle = true;
  1766. lctx.type.isLValue = true;
  1767. asSExprContext ctx(engine);
  1768. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  1769. if( !lctx.type.dataType.IsPrimitive() )
  1770. ctx.bc.Pop(AS_PTR_SIZE);
  1771. // Release temporary variables used by expression
  1772. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1773. ProcessDeferredParams(&ctx);
  1774. bc->AddCode(&ctx.bc);
  1775. }
  1776. el = el->next;
  1777. index++;
  1778. }
  1779. }
  1780. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  1781. {
  1782. *hasReturn = false;
  1783. if( statement->nodeType == snStatementBlock )
  1784. CompileStatementBlock(statement, true, hasReturn, bc);
  1785. else if( statement->nodeType == snIf )
  1786. CompileIfStatement(statement, hasReturn, bc);
  1787. else if( statement->nodeType == snFor )
  1788. CompileForStatement(statement, bc);
  1789. else if( statement->nodeType == snWhile )
  1790. CompileWhileStatement(statement, bc);
  1791. else if( statement->nodeType == snDoWhile )
  1792. CompileDoWhileStatement(statement, bc);
  1793. else if( statement->nodeType == snExpressionStatement )
  1794. CompileExpressionStatement(statement, bc);
  1795. else if( statement->nodeType == snBreak )
  1796. CompileBreakStatement(statement, bc);
  1797. else if( statement->nodeType == snContinue )
  1798. CompileContinueStatement(statement, bc);
  1799. else if( statement->nodeType == snSwitch )
  1800. CompileSwitchStatement(statement, hasReturn, bc);
  1801. else if( statement->nodeType == snReturn )
  1802. {
  1803. CompileReturnStatement(statement, bc);
  1804. *hasReturn = true;
  1805. }
  1806. }
  1807. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  1808. {
  1809. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  1810. // Reserve label for break statements
  1811. int breakLabel = nextLabel++;
  1812. breakLabels.PushLast(breakLabel);
  1813. // Add a variable scope that will be used by CompileBreak
  1814. // to know where to stop deallocating variables
  1815. AddVariableScope(true, false);
  1816. //---------------------------
  1817. // Compile the switch expression
  1818. //-------------------------------
  1819. // Compile the switch expression
  1820. asSExprContext expr(engine);
  1821. CompileAssignment(snode->firstChild, &expr);
  1822. // Verify that the expression is a primitive type
  1823. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
  1824. {
  1825. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  1826. return;
  1827. }
  1828. ProcessPropertyGetAccessor(&expr, snode);
  1829. // TODO: Need to support 64bit integers
  1830. // Convert the expression to a 32bit variable
  1831. asCDataType to;
  1832. if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
  1833. to.SetTokenType(ttInt);
  1834. else if( expr.type.dataType.IsUnsignedType() )
  1835. to.SetTokenType(ttUInt);
  1836. // Make sure the value is in a variable
  1837. if( expr.type.dataType.IsReference() )
  1838. ConvertToVariable(&expr);
  1839. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  1840. ConvertToVariable(&expr);
  1841. int offset = expr.type.stackOffset;
  1842. ProcessDeferredParams(&expr);
  1843. //-------------------------------
  1844. // Determine case values and labels
  1845. //--------------------------------
  1846. // Remember the first label so that we can later pass the
  1847. // correct label to each CompileCase()
  1848. int firstCaseLabel = nextLabel;
  1849. int defaultLabel = 0;
  1850. asCArray<int> caseValues;
  1851. asCArray<int> caseLabels;
  1852. // Compile all case comparisons and make them jump to the right label
  1853. asCScriptNode *cnode = snode->firstChild->next;
  1854. while( cnode )
  1855. {
  1856. // Each case should have a constant expression
  1857. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1858. {
  1859. // Compile expression
  1860. asSExprContext c(engine);
  1861. CompileExpression(cnode->firstChild, &c);
  1862. // Verify that the result is a constant
  1863. if( !c.type.isConstant )
  1864. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  1865. // Verify that the result is an integral number
  1866. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
  1867. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  1868. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  1869. // Has this case been declared already?
  1870. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  1871. {
  1872. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  1873. }
  1874. // TODO: Optimize: We can insert the numbers sorted already
  1875. // Store constant for later use
  1876. caseValues.PushLast(c.type.intValue);
  1877. // Reserve label for this case
  1878. caseLabels.PushLast(nextLabel++);
  1879. }
  1880. else
  1881. {
  1882. // Is default the last case?
  1883. if( cnode->next )
  1884. {
  1885. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  1886. break;
  1887. }
  1888. // Reserve label for this case
  1889. defaultLabel = nextLabel++;
  1890. }
  1891. cnode = cnode->next;
  1892. }
  1893. // check for empty switch
  1894. if (caseValues.GetLength() == 0)
  1895. {
  1896. Error(TXT_EMPTY_SWITCH, snode);
  1897. return;
  1898. }
  1899. if( defaultLabel == 0 )
  1900. defaultLabel = breakLabel;
  1901. //---------------------------------
  1902. // Output the optimized case comparisons
  1903. // with jumps to the case code
  1904. //------------------------------------
  1905. // Sort the case values by increasing value. Do the sort together with the labels
  1906. // A simple bubble sort is sufficient since we don't expect a huge number of values
  1907. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  1908. {
  1909. for( int bck = fwd - 1; bck >= 0; bck-- )
  1910. {
  1911. int bckp = bck + 1;
  1912. if( caseValues[bck] > caseValues[bckp] )
  1913. {
  1914. // Swap the values in both arrays
  1915. int swap = caseValues[bckp];
  1916. caseValues[bckp] = caseValues[bck];
  1917. caseValues[bck] = swap;
  1918. swap = caseLabels[bckp];
  1919. caseLabels[bckp] = caseLabels[bck];
  1920. caseLabels[bck] = swap;
  1921. }
  1922. else
  1923. break;
  1924. }
  1925. }
  1926. // Find ranges of consecutive numbers
  1927. asCArray<int> ranges;
  1928. ranges.PushLast(0);
  1929. asUINT n;
  1930. for( n = 1; n < caseValues.GetLength(); ++n )
  1931. {
  1932. // We can join numbers that are less than 5 numbers
  1933. // apart since the output code will still be smaller
  1934. if( caseValues[n] > caseValues[n-1] + 5 )
  1935. ranges.PushLast(n);
  1936. }
  1937. // If the value is larger than the largest case value, jump to default
  1938. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1939. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  1940. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1941. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  1942. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1943. // TODO: optimize: We could possibly optimize this even more by doing a
  1944. // binary search instead of a linear search through the ranges
  1945. // For each range
  1946. int range;
  1947. for( range = 0; range < (int)ranges.GetLength(); range++ )
  1948. {
  1949. // Find the largest value in this range
  1950. int maxRange = caseValues[ranges[range]];
  1951. int index = ranges[range];
  1952. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  1953. maxRange = caseValues[index];
  1954. // If there are only 2 numbers then it is better to compare them directly
  1955. if( index - ranges[range] > 2 )
  1956. {
  1957. // If the value is smaller than the smallest case value in the range, jump to default
  1958. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1959. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1960. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1961. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  1962. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1963. int nextRangeLabel = nextLabel++;
  1964. // If this is the last range we don't have to make this test
  1965. if( range < (int)ranges.GetLength() - 1 )
  1966. {
  1967. // If the value is larger than the largest case value in the range, jump to the next range
  1968. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1969. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  1970. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1971. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  1972. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1973. }
  1974. // Jump forward according to the value
  1975. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1976. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1977. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  1978. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1979. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  1980. // Add the list of jumps to the correct labels (any holes, jump to default)
  1981. index = ranges[range];
  1982. for( int n = caseValues[index]; n <= maxRange; n++ )
  1983. {
  1984. if( caseValues[index] == n )
  1985. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  1986. else
  1987. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  1988. }
  1989. expr.bc.Label((short)nextRangeLabel);
  1990. }
  1991. else
  1992. {
  1993. // Simply make a comparison with each value
  1994. int n;
  1995. for( n = ranges[range]; n < index; ++n )
  1996. {
  1997. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1998. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  1999. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2000. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2001. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2002. }
  2003. }
  2004. }
  2005. // Catch any value that falls trough
  2006. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2007. // Release the temporary variable previously stored
  2008. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2009. //----------------------------------
  2010. // Output case implementations
  2011. //----------------------------------
  2012. // Compile case implementations, each one with the label before it
  2013. cnode = snode->firstChild->next;
  2014. while( cnode )
  2015. {
  2016. // Each case should have a constant expression
  2017. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2018. {
  2019. expr.bc.Label((short)firstCaseLabel++);
  2020. CompileCase(cnode->firstChild->next, &expr.bc);
  2021. }
  2022. else
  2023. {
  2024. expr.bc.Label((short)defaultLabel);
  2025. // Is default the last case?
  2026. if( cnode->next )
  2027. {
  2028. // We've already reported this error
  2029. break;
  2030. }
  2031. CompileCase(cnode->firstChild, &expr.bc);
  2032. }
  2033. cnode = cnode->next;
  2034. }
  2035. //--------------------------------
  2036. bc->AddCode(&expr.bc);
  2037. // Add break label
  2038. bc->Label((short)breakLabel);
  2039. breakLabels.PopLast();
  2040. RemoveVariableScope();
  2041. }
  2042. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2043. {
  2044. bool isFinished = false;
  2045. bool hasReturn = false;
  2046. while( node )
  2047. {
  2048. if( hasReturn || isFinished )
  2049. {
  2050. Warning(TXT_UNREACHABLE_CODE, node);
  2051. break;
  2052. }
  2053. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2054. isFinished = true;
  2055. asCByteCode statement(engine);
  2056. if( node->nodeType == snDeclaration )
  2057. {
  2058. Error(TXT_DECL_IN_SWITCH, node);
  2059. // Compile it anyway to avoid further compiler errors
  2060. CompileDeclaration(node, &statement);
  2061. }
  2062. else
  2063. CompileStatement(node, &hasReturn, &statement);
  2064. LineInstr(bc, node->tokenPos);
  2065. bc->AddCode(&statement);
  2066. if( !hasCompileErrors )
  2067. asASSERT( tempVariables.GetLength() == 0 );
  2068. node = node->next;
  2069. }
  2070. }
  2071. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2072. {
  2073. // We will use one label for the if statement
  2074. // and possibly another for the else statement
  2075. int afterLabel = nextLabel++;
  2076. // Compile the expression
  2077. asSExprContext expr(engine);
  2078. CompileAssignment(inode->firstChild, &expr);
  2079. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2080. {
  2081. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2082. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2083. }
  2084. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2085. ProcessDeferredParams(&expr);
  2086. if( !expr.type.isConstant )
  2087. {
  2088. ProcessPropertyGetAccessor(&expr, inode);
  2089. ConvertToVariable(&expr);
  2090. // Add byte code from the expression
  2091. bc->AddCode(&expr.bc);
  2092. // Add a test
  2093. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2094. bc->Instr(asBC_ClrHi);
  2095. bc->InstrDWORD(asBC_JZ, afterLabel);
  2096. ReleaseTemporaryVariable(expr.type, bc);
  2097. }
  2098. else if( expr.type.dwordValue == 0 )
  2099. {
  2100. // Jump to the else case
  2101. bc->InstrINT(asBC_JMP, afterLabel);
  2102. // TODO: Should we warn that the expression will always go to the else?
  2103. }
  2104. // Compile the if statement
  2105. bool origIsConstructorCalled = m_isConstructorCalled;
  2106. bool hasReturn1;
  2107. asCByteCode ifBC(engine);
  2108. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2109. // Add the byte code
  2110. LineInstr(bc, inode->firstChild->next->tokenPos);
  2111. bc->AddCode(&ifBC);
  2112. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2113. {
  2114. // Don't allow if( expr );
  2115. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2116. }
  2117. // If one of the statements call the constructor, the other must as well
  2118. // otherwise it is possible the constructor is never called
  2119. bool constructorCall1 = false;
  2120. bool constructorCall2 = false;
  2121. if( !origIsConstructorCalled && m_isConstructorCalled )
  2122. constructorCall1 = true;
  2123. // Do we have an else statement?
  2124. if( inode->firstChild->next != inode->lastChild )
  2125. {
  2126. // Reset the constructor called flag so the else statement can call the constructor too
  2127. m_isConstructorCalled = origIsConstructorCalled;
  2128. int afterElse = 0;
  2129. if( !hasReturn1 )
  2130. {
  2131. afterElse = nextLabel++;
  2132. // Add jump to after the else statement
  2133. bc->InstrINT(asBC_JMP, afterElse);
  2134. }
  2135. // Add label for the else statement
  2136. bc->Label((short)afterLabel);
  2137. bool hasReturn2;
  2138. asCByteCode elseBC(engine);
  2139. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2140. // Add byte code for the else statement
  2141. LineInstr(bc, inode->lastChild->tokenPos);
  2142. bc->AddCode(&elseBC);
  2143. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2144. {
  2145. // Don't allow if( expr ) {} else;
  2146. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2147. }
  2148. if( !hasReturn1 )
  2149. {
  2150. // Add label for the end of else statement
  2151. bc->Label((short)afterElse);
  2152. }
  2153. // The if statement only has return if both alternatives have
  2154. *hasReturn = hasReturn1 && hasReturn2;
  2155. if( !origIsConstructorCalled && m_isConstructorCalled )
  2156. constructorCall2 = true;
  2157. }
  2158. else
  2159. {
  2160. // Add label for the end of if statement
  2161. bc->Label((short)afterLabel);
  2162. *hasReturn = false;
  2163. }
  2164. // Make sure both or neither conditions call a constructor
  2165. if( (constructorCall1 && !constructorCall2) ||
  2166. (constructorCall2 && !constructorCall1) )
  2167. {
  2168. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2169. }
  2170. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2171. }
  2172. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2173. {
  2174. // TODO: optimize: We should be able to remove the static JMP to the beginning of the loop by rearranging the
  2175. // byte code a bit.
  2176. //
  2177. // init
  2178. // jump to before
  2179. // begin:
  2180. // statements
  2181. // continue:
  2182. // next
  2183. // before:
  2184. // condition
  2185. // if loop jump to begin
  2186. // break:
  2187. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2188. AddVariableScope(true, true);
  2189. // We will use three labels for the for loop
  2190. int beforeLabel = nextLabel++;
  2191. int afterLabel = nextLabel++;
  2192. int continueLabel = nextLabel++;
  2193. continueLabels.PushLast(continueLabel);
  2194. breakLabels.PushLast(afterLabel);
  2195. //---------------------------------------
  2196. // Compile the initialization statement
  2197. asCByteCode initBC(engine);
  2198. if( fnode->firstChild->nodeType == snDeclaration )
  2199. CompileDeclaration(fnode->firstChild, &initBC);
  2200. else
  2201. CompileExpressionStatement(fnode->firstChild, &initBC);
  2202. //-----------------------------------
  2203. // Compile the condition statement
  2204. asSExprContext expr(engine);
  2205. asCScriptNode *second = fnode->firstChild->next;
  2206. if( second->firstChild )
  2207. {
  2208. int r = CompileAssignment(second->firstChild, &expr);
  2209. if( r >= 0 )
  2210. {
  2211. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2212. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2213. else
  2214. {
  2215. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2216. ProcessDeferredParams(&expr);
  2217. ProcessPropertyGetAccessor(&expr, second);
  2218. // If expression is false exit the loop
  2219. ConvertToVariable(&expr);
  2220. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2221. expr.bc.Instr(asBC_ClrHi);
  2222. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2223. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2224. }
  2225. }
  2226. }
  2227. //---------------------------
  2228. // Compile the increment statement
  2229. asCByteCode nextBC(engine);
  2230. asCScriptNode *third = second->next;
  2231. if( third->nodeType == snExpressionStatement )
  2232. CompileExpressionStatement(third, &nextBC);
  2233. //------------------------------
  2234. // Compile loop statement
  2235. bool hasReturn;
  2236. asCByteCode forBC(engine);
  2237. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2238. //-------------------------------
  2239. // Join the code pieces
  2240. bc->AddCode(&initBC);
  2241. bc->Label((short)beforeLabel);
  2242. // Add a suspend bytecode inside the loop to guarantee
  2243. // that the application can suspend the execution
  2244. bc->Instr(asBC_SUSPEND);
  2245. bc->InstrWORD(asBC_JitEntry, 0);
  2246. bc->AddCode(&expr.bc);
  2247. LineInstr(bc, fnode->lastChild->tokenPos);
  2248. bc->AddCode(&forBC);
  2249. bc->Label((short)continueLabel);
  2250. bc->AddCode(&nextBC);
  2251. bc->InstrINT(asBC_JMP, beforeLabel);
  2252. bc->Label((short)afterLabel);
  2253. continueLabels.PopLast();
  2254. breakLabels.PopLast();
  2255. // Deallocate variables in this block, in reverse order
  2256. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2257. {
  2258. sVariable *v = variables->variables[n];
  2259. // Call variable destructors here, for variables not yet destroyed
  2260. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2261. // Don't deallocate function parameters
  2262. if( v->stackOffset > 0 )
  2263. DeallocateVariable(v->stackOffset);
  2264. }
  2265. RemoveVariableScope();
  2266. }
  2267. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2268. {
  2269. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2270. AddVariableScope(true, true);
  2271. // We will use two labels for the while loop
  2272. int beforeLabel = nextLabel++;
  2273. int afterLabel = nextLabel++;
  2274. continueLabels.PushLast(beforeLabel);
  2275. breakLabels.PushLast(afterLabel);
  2276. // Add label before the expression
  2277. bc->Label((short)beforeLabel);
  2278. // Compile expression
  2279. asSExprContext expr(engine);
  2280. CompileAssignment(wnode->firstChild, &expr);
  2281. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2282. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2283. else
  2284. {
  2285. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2286. ProcessDeferredParams(&expr);
  2287. ProcessPropertyGetAccessor(&expr, wnode);
  2288. // Add byte code for the expression
  2289. ConvertToVariable(&expr);
  2290. bc->AddCode(&expr.bc);
  2291. // Jump to end of statement if expression is false
  2292. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2293. bc->Instr(asBC_ClrHi);
  2294. bc->InstrDWORD(asBC_JZ, afterLabel);
  2295. ReleaseTemporaryVariable(expr.type, bc);
  2296. }
  2297. // Add a suspend bytecode inside the loop to guarantee
  2298. // that the application can suspend the execution
  2299. bc->Instr(asBC_SUSPEND);
  2300. bc->InstrWORD(asBC_JitEntry, 0);
  2301. // Compile statement
  2302. bool hasReturn;
  2303. asCByteCode whileBC(engine);
  2304. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2305. // Add byte code for the statement
  2306. LineInstr(bc, wnode->lastChild->tokenPos);
  2307. bc->AddCode(&whileBC);
  2308. // Jump to the expression
  2309. bc->InstrINT(asBC_JMP, beforeLabel);
  2310. // Add label after the statement
  2311. bc->Label((short)afterLabel);
  2312. continueLabels.PopLast();
  2313. breakLabels.PopLast();
  2314. RemoveVariableScope();
  2315. }
  2316. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2317. {
  2318. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2319. AddVariableScope(true, true);
  2320. // We will use two labels for the while loop
  2321. int beforeLabel = nextLabel++;
  2322. int beforeTest = nextLabel++;
  2323. int afterLabel = nextLabel++;
  2324. continueLabels.PushLast(beforeTest);
  2325. breakLabels.PushLast(afterLabel);
  2326. // Add label before the statement
  2327. bc->Label((short)beforeLabel);
  2328. // Compile statement
  2329. bool hasReturn;
  2330. asCByteCode whileBC(engine);
  2331. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2332. // Add byte code for the statement
  2333. LineInstr(bc, wnode->firstChild->tokenPos);
  2334. bc->AddCode(&whileBC);
  2335. // Add label before the expression
  2336. bc->Label((short)beforeTest);
  2337. // Add a suspend bytecode inside the loop to guarantee
  2338. // that the application can suspend the execution
  2339. bc->Instr(asBC_SUSPEND);
  2340. bc->InstrWORD(asBC_JitEntry, 0);
  2341. // Add a line instruction
  2342. LineInstr(bc, wnode->lastChild->tokenPos);
  2343. // Compile expression
  2344. asSExprContext expr(engine);
  2345. CompileAssignment(wnode->lastChild, &expr);
  2346. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2347. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2348. else
  2349. {
  2350. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2351. ProcessDeferredParams(&expr);
  2352. ProcessPropertyGetAccessor(&expr, wnode);
  2353. // Add byte code for the expression
  2354. ConvertToVariable(&expr);
  2355. bc->AddCode(&expr.bc);
  2356. // Jump to next iteration if expression is true
  2357. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2358. bc->Instr(asBC_ClrHi);
  2359. bc->InstrDWORD(asBC_JNZ, beforeLabel);
  2360. ReleaseTemporaryVariable(expr.type, bc);
  2361. }
  2362. // Add label after the statement
  2363. bc->Label((short)afterLabel);
  2364. continueLabels.PopLast();
  2365. breakLabels.PopLast();
  2366. RemoveVariableScope();
  2367. }
  2368. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2369. {
  2370. if( breakLabels.GetLength() == 0 )
  2371. {
  2372. Error(TXT_INVALID_BREAK, node);
  2373. return;
  2374. }
  2375. // Add destructor calls for all variables that will go out of scope
  2376. // Put this clean up in a block to allow exception handler to understand them
  2377. bc->Block(true);
  2378. asCVariableScope *vs = variables;
  2379. while( !vs->isBreakScope )
  2380. {
  2381. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2382. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2383. vs = vs->parent;
  2384. }
  2385. bc->Block(false);
  2386. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2387. }
  2388. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2389. {
  2390. if( continueLabels.GetLength() == 0 )
  2391. {
  2392. Error(TXT_INVALID_CONTINUE, node);
  2393. return;
  2394. }
  2395. // Add destructor calls for all variables that will go out of scope
  2396. // Put this clean up in a block to allow exception handler to understand them
  2397. bc->Block(true);
  2398. asCVariableScope *vs = variables;
  2399. while( !vs->isContinueScope )
  2400. {
  2401. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2402. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2403. vs = vs->parent;
  2404. }
  2405. bc->Block(false);
  2406. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2407. }
  2408. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2409. {
  2410. if( enode->firstChild )
  2411. {
  2412. // Compile the expression
  2413. asSExprContext expr(engine);
  2414. CompileAssignment(enode->firstChild, &expr);
  2415. // Pop the value from the stack
  2416. if( !expr.type.dataType.IsPrimitive() )
  2417. expr.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  2418. // Release temporary variables used by expression
  2419. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2420. ProcessDeferredParams(&expr);
  2421. bc->AddCode(&expr.bc);
  2422. }
  2423. }
  2424. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, asCArray<int> *reservedVars, bool forceOnHeap)
  2425. {
  2426. // If the object already is stored in temporary variable then nothing needs to be done
  2427. // Note, a type can be temporary without being a variable, in which case it is holding off
  2428. // on releasing a previously used object.
  2429. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2430. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2431. {
  2432. // If the temporary object is currently not a reference
  2433. // the expression needs to be reevaluated to a reference
  2434. if( !ctx->type.dataType.IsReference() )
  2435. {
  2436. ctx->bc.Pop(AS_PTR_SIZE);
  2437. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2438. ctx->type.dataType.MakeReference(true);
  2439. }
  2440. return;
  2441. }
  2442. // Allocate temporary variable
  2443. asCDataType dt = ctx->type.dataType;
  2444. dt.MakeReference(false);
  2445. dt.MakeReadOnly(false);
  2446. int offset = AllocateVariableNotIn(dt, true, reservedVars, forceOnHeap);
  2447. // Objects stored on the stack are not considered references
  2448. dt.MakeReference(IsVariableOnHeap(offset));
  2449. asCTypeInfo lvalue;
  2450. lvalue.Set(dt);
  2451. lvalue.isTemporary = true;
  2452. lvalue.stackOffset = (short)offset;
  2453. lvalue.isVariable = true;
  2454. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2455. if( (!dt.IsObjectHandle() || (dt.GetObjectType() && (dt.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  2456. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2457. {
  2458. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2459. // Use the copy constructor/factory when available
  2460. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2461. }
  2462. else
  2463. {
  2464. // Allocate and construct the temporary object
  2465. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2466. // Assign the object to the temporary variable
  2467. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2468. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2469. PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2470. // Pop the original reference
  2471. ctx->bc.Pop(AS_PTR_SIZE);
  2472. }
  2473. // If the expression was holding off on releasing a
  2474. // previously used object, we need to release it now
  2475. if( ctx->type.isTemporary )
  2476. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2477. // Push the reference to the temporary variable on the stack
  2478. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2479. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2480. ctx->type = lvalue;
  2481. }
  2482. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2483. {
  2484. // Get return type and location
  2485. sVariable *v = variables->GetVariable("return");
  2486. // Basic validations
  2487. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2488. {
  2489. Error(TXT_MUST_RETURN_VALUE, rnode);
  2490. return;
  2491. }
  2492. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2493. {
  2494. Error(TXT_CANT_RETURN_VALUE, rnode);
  2495. return;
  2496. }
  2497. // Compile the expression
  2498. if( rnode->firstChild )
  2499. {
  2500. // Compile the expression
  2501. asSExprContext expr(engine);
  2502. int r = CompileAssignment(rnode->firstChild, &expr);
  2503. if( r < 0 ) return;
  2504. if( v->type.IsReference() )
  2505. {
  2506. // The expression that gives the reference must not use any of the
  2507. // variables that must be destroyed upon exit, because then it means
  2508. // reference will stay alive while the clean-up is done, which could
  2509. // potentially mean that the reference is invalidated by the clean-up.
  2510. //
  2511. // When the function is returning a reference, the clean-up of the
  2512. // variables must be done before the evaluation of the expression.
  2513. //
  2514. // A reference to a global variable, or a class member for class methods
  2515. // should be allowed to be returned.
  2516. if( !(expr.type.dataType.IsReference() ||
  2517. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2518. {
  2519. // Clean up the potential deferred parameters
  2520. ProcessDeferredParams(&expr);
  2521. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2522. return;
  2523. }
  2524. // No references to local variables, temporary variables, or parameters
  2525. // are allowed to be returned, since they go out of scope when the function
  2526. // returns. Even reference parameters are disallowed, since it is not possible
  2527. // to know the scope of them. The exception is the 'this' pointer, which
  2528. // is treated by the compiler as a local variable, but isn't really so.
  2529. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2530. {
  2531. // Clean up the potential deferred parameters
  2532. ProcessDeferredParams(&expr);
  2533. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2534. return;
  2535. }
  2536. // The type must match exactly as we cannot convert
  2537. // the reference without loosing the original value
  2538. if( !(v->type == expr.type.dataType ||
  2539. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRef(expr.type.dataType))) )
  2540. {
  2541. // Clean up the potential deferred parameters
  2542. ProcessDeferredParams(&expr);
  2543. asCString str;
  2544. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2545. Error(str.AddressOf(), rnode);
  2546. return;
  2547. }
  2548. // The expression must not have any deferred expressions, because the evaluation
  2549. // of these cannot be done without keeping the reference which is not safe
  2550. if( expr.deferredParams.GetLength() )
  2551. {
  2552. // Clean up the potential deferred parameters
  2553. ProcessDeferredParams(&expr);
  2554. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2555. return;
  2556. }
  2557. // Make sure the expression isn't using any local variables that
  2558. // will need to be cleaned up before the function completes
  2559. asCArray<int> usedVars;
  2560. expr.bc.GetVarsUsed(usedVars);
  2561. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  2562. {
  2563. int var = GetVariableSlot(usedVars[n]);
  2564. if( var != -1 )
  2565. {
  2566. asCDataType dt = variableAllocations[var];
  2567. if( dt.IsObject() )
  2568. {
  2569. ProcessDeferredParams(&expr);
  2570. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  2571. return;
  2572. }
  2573. }
  2574. }
  2575. // All objects in the function must be cleaned up before the expression
  2576. // is evaluated, otherwise there is a possibility that the cleanup will
  2577. // invalidate the reference.
  2578. // Destroy the local variables before loading
  2579. // the reference into the register. This will
  2580. // be done before the expression is evaluated.
  2581. DestroyVariables(bc);
  2582. // For primitives the reference is already in the register,
  2583. // but for non-primitives the reference is on the stack so we
  2584. // need to load it into the register
  2585. if( !expr.type.dataType.IsPrimitive() )
  2586. {
  2587. if( (!expr.type.dataType.IsObjectHandle() || (expr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) &&
  2588. expr.type.dataType.IsReference() )
  2589. expr.bc.Instr(asBC_RDSPTR);
  2590. expr.bc.Instr(asBC_PopRPtr);
  2591. }
  2592. // There are no temporaries to release so we're done
  2593. }
  2594. else // if( !v->type.IsReference() )
  2595. {
  2596. ProcessPropertyGetAccessor(&expr, rnode);
  2597. // Prepare the value for assignment
  2598. IsVariableInitialized(&expr.type, rnode->firstChild);
  2599. if( v->type.IsPrimitive() )
  2600. {
  2601. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2602. // Implicitly convert the value to the return type
  2603. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2604. // Verify that the conversion was successful
  2605. if( expr.type.dataType != v->type )
  2606. {
  2607. asCString str;
  2608. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2609. Error(str.AddressOf(), rnode);
  2610. return;
  2611. }
  2612. else
  2613. {
  2614. ConvertToVariable(&expr);
  2615. // Clean up the local variables and process deferred parameters
  2616. DestroyVariables(&expr.bc);
  2617. ProcessDeferredParams(&expr);
  2618. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2619. // Load the variable in the register
  2620. if( v->type.GetSizeOnStackDWords() == 1 )
  2621. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2622. else
  2623. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  2624. }
  2625. }
  2626. else if( v->type.IsObject() )
  2627. {
  2628. #ifndef AS_OLD
  2629. // Value types are returned on the stack, in a location
  2630. // that has been reserved by the calling function.
  2631. if( outFunc->DoesReturnOnStack() )
  2632. {
  2633. // TODO: optimize: If the return type has a constructor that takes the type of the expression,
  2634. // it should be called directly instead of first converting the expression and
  2635. // then copy the value.
  2636. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2637. {
  2638. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2639. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2640. {
  2641. asCString str;
  2642. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2643. Error(str.AddressOf(), rnode->firstChild);
  2644. return;
  2645. }
  2646. }
  2647. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  2648. if( v->type.GetObjectType()->beh.copyconstruct )
  2649. {
  2650. PrepareForAssignment(&v->type, &expr, rnode->firstChild);
  2651. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  2652. }
  2653. else
  2654. {
  2655. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  2656. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, false, true);
  2657. PrepareForAssignment(&v->type, &expr, rnode->firstChild);
  2658. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2659. expr.bc.Instr(asBC_RDSPTR);
  2660. asSExprContext lexpr(engine);
  2661. lexpr.type.Set(v->type);
  2662. lexpr.type.isLValue = true;
  2663. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  2664. expr.bc.Pop(AS_PTR_SIZE);
  2665. // Release any temporary variable
  2666. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2667. }
  2668. // Clean up the local variables and process deferred parameters
  2669. DestroyVariables(&expr.bc);
  2670. ProcessDeferredParams(&expr);
  2671. }
  2672. else
  2673. #endif
  2674. {
  2675. #ifndef AS_OLD
  2676. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  2677. #endif
  2678. // Prepare the expression to be loaded into the object
  2679. // register. This will place the reference in local variable
  2680. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0, 0, true);
  2681. // Pop the reference to the temporary variable
  2682. expr.bc.Pop(AS_PTR_SIZE);
  2683. // Clean up the local variables and process deferred parameters
  2684. DestroyVariables(&expr.bc);
  2685. ProcessDeferredParams(&expr);
  2686. // Load the object pointer into the object register
  2687. // LOADOBJ also clears the address in the variable
  2688. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  2689. // LOADOBJ cleared the address in the variable so the object will not be freed
  2690. // here, but the temporary variable must still be freed so the slot can be reused
  2691. // By releasing without the bytecode we do just that.
  2692. ReleaseTemporaryVariable(expr.type, 0);
  2693. }
  2694. }
  2695. }
  2696. bc->AddCode(&expr.bc);
  2697. }
  2698. else
  2699. {
  2700. // For functions that don't return anything
  2701. // we just detroy the local variables
  2702. DestroyVariables(bc);
  2703. }
  2704. // Jump to the end of the function
  2705. bc->InstrINT(asBC_JMP, 0);
  2706. }
  2707. void asCCompiler::DestroyVariables(asCByteCode *bc)
  2708. {
  2709. // Call destructor on all variables except for the function parameters
  2710. // Put the clean-up in a block to allow exception handler to understand this
  2711. bc->Block(true);
  2712. asCVariableScope *vs = variables;
  2713. while( vs )
  2714. {
  2715. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2716. if( vs->variables[n]->stackOffset > 0 )
  2717. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2718. vs = vs->parent;
  2719. }
  2720. bc->Block(false);
  2721. }
  2722. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  2723. {
  2724. variables = asNEW(asCVariableScope)(variables);
  2725. variables->isBreakScope = isBreakScope;
  2726. variables->isContinueScope = isContinueScope;
  2727. }
  2728. void asCCompiler::RemoveVariableScope()
  2729. {
  2730. if( variables )
  2731. {
  2732. asCVariableScope *var = variables;
  2733. variables = variables->parent;
  2734. asDELETE(var,asCVariableScope);
  2735. }
  2736. }
  2737. void asCCompiler::Error(const char *msg, asCScriptNode *node)
  2738. {
  2739. asCString str;
  2740. int r = 0, c = 0;
  2741. asASSERT( node );
  2742. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2743. builder->WriteError(script->name.AddressOf(), msg, r, c);
  2744. hasCompileErrors = true;
  2745. }
  2746. void asCCompiler::Warning(const char *msg, asCScriptNode *node)
  2747. {
  2748. asCString str;
  2749. int r = 0, c = 0;
  2750. asASSERT( node );
  2751. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2752. builder->WriteWarning(script->name.AddressOf(), msg, r, c);
  2753. }
  2754. void asCCompiler::Information(const char *msg, asCScriptNode *node)
  2755. {
  2756. asCString str;
  2757. int r = 0, c = 0;
  2758. asASSERT( node );
  2759. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2760. builder->WriteInfo(script->name.AddressOf(), msg, r, c, false);
  2761. }
  2762. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  2763. {
  2764. int r = 0, c = 0;
  2765. asASSERT( node );
  2766. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2767. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  2768. {
  2769. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  2770. builder->WriteInfo(script->name.AddressOf(), func->GetDeclaration(true), r, c, false);
  2771. }
  2772. }
  2773. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  2774. {
  2775. return AllocateVariableNotIn(type, isTemporary, 0, forceOnHeap);
  2776. }
  2777. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, asCArray<int> *vars, bool forceOnHeap)
  2778. {
  2779. asCDataType t(type);
  2780. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  2781. t.SetTokenType(ttInt);
  2782. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  2783. t.SetTokenType(ttDouble);
  2784. // Only null handles have the token type unrecognized token
  2785. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  2786. bool isOnHeap = true;
  2787. // TODO: Remove this once the bugs with value types on stack is fixed
  2788. // forceOnHeap = true;
  2789. if( t.IsPrimitive() ||
  2790. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  2791. {
  2792. // Primitives and value types (unless overridden) are allocated on the stack
  2793. isOnHeap = false;
  2794. }
  2795. // Find a free location with the same type
  2796. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  2797. {
  2798. int slot = freeVariables[n];
  2799. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  2800. variableIsTemporary[slot] == isTemporary &&
  2801. variableIsOnHeap[slot] == isOnHeap )
  2802. {
  2803. // We can't return by slot, must count variable sizes
  2804. int offset = GetVariableOffset(slot);
  2805. // Verify that it is not in the list of used variables
  2806. bool isUsed = false;
  2807. if( vars )
  2808. {
  2809. for( asUINT m = 0; m < vars->GetLength(); m++ )
  2810. {
  2811. if( offset == (*vars)[m] )
  2812. {
  2813. isUsed = true;
  2814. break;
  2815. }
  2816. }
  2817. }
  2818. if( !isUsed )
  2819. {
  2820. if( n != freeVariables.GetLength() - 1 )
  2821. freeVariables[n] = freeVariables.PopLast();
  2822. else
  2823. freeVariables.PopLast();
  2824. if( isTemporary )
  2825. tempVariables.PushLast(offset);
  2826. return offset;
  2827. }
  2828. }
  2829. }
  2830. variableAllocations.PushLast(t);
  2831. variableIsTemporary.PushLast(isTemporary);
  2832. variableIsOnHeap.PushLast(isOnHeap);
  2833. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  2834. if( isTemporary )
  2835. tempVariables.PushLast(offset);
  2836. return offset;
  2837. }
  2838. int asCCompiler::GetVariableOffset(int varIndex)
  2839. {
  2840. // Return offset to the last dword on the stack
  2841. int varOffset = 1;
  2842. for( int n = 0; n < varIndex; n++ )
  2843. {
  2844. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2845. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  2846. else
  2847. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  2848. }
  2849. if( varIndex < (int)variableAllocations.GetLength() )
  2850. {
  2851. int size;
  2852. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  2853. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  2854. else
  2855. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  2856. if( size > 1 )
  2857. varOffset += size-1;
  2858. }
  2859. return varOffset;
  2860. }
  2861. int asCCompiler::GetVariableSlot(int offset)
  2862. {
  2863. int varOffset = 1;
  2864. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  2865. {
  2866. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2867. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  2868. else
  2869. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  2870. if( varOffset == offset )
  2871. return n;
  2872. varOffset++;
  2873. }
  2874. return -1;
  2875. }
  2876. bool asCCompiler::IsVariableOnHeap(int offset)
  2877. {
  2878. int varSlot = GetVariableSlot(offset);
  2879. if( varSlot < 0 )
  2880. {
  2881. // This happens for function arguments that are considered as on the heap
  2882. return true;
  2883. }
  2884. return variableIsOnHeap[varSlot];
  2885. }
  2886. void asCCompiler::DeallocateVariable(int offset)
  2887. {
  2888. // Remove temporary variable
  2889. int n;
  2890. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  2891. {
  2892. if( offset == tempVariables[n] )
  2893. {
  2894. if( n == (int)tempVariables.GetLength()-1 )
  2895. tempVariables.PopLast();
  2896. else
  2897. tempVariables[n] = tempVariables.PopLast();
  2898. break;
  2899. }
  2900. }
  2901. n = GetVariableSlot(offset);
  2902. if( n != -1 )
  2903. {
  2904. freeVariables.PushLast(n);
  2905. return;
  2906. }
  2907. // We might get here if the variable was implicitly declared
  2908. // because it was use before a formal declaration, in this case
  2909. // the offset is 0x7FFF
  2910. asASSERT(offset == 0x7FFF);
  2911. }
  2912. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  2913. {
  2914. if( t.isTemporary )
  2915. {
  2916. ReleaseTemporaryVariable(t.stackOffset, bc);
  2917. t.isTemporary = false;
  2918. }
  2919. }
  2920. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  2921. {
  2922. if( bc )
  2923. {
  2924. // We need to call the destructor on the true variable type
  2925. int n = GetVariableSlot(offset);
  2926. asASSERT( n >= 0 );
  2927. if( n >= 0 )
  2928. {
  2929. asCDataType dt = variableAllocations[n];
  2930. bool isOnHeap = variableIsOnHeap[n];
  2931. // Call destructor
  2932. CallDestructor(dt, offset, isOnHeap, bc);
  2933. }
  2934. }
  2935. DeallocateVariable(offset);
  2936. }
  2937. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  2938. {
  2939. if( ctx->type.dataType.IsReference() )
  2940. {
  2941. if( ctx->type.dataType.IsObject() )
  2942. {
  2943. ctx->type.dataType.MakeReference(false);
  2944. if( generateCode )
  2945. {
  2946. ctx->bc.Instr(asBC_CHKREF);
  2947. ctx->bc.Instr(asBC_RDSPTR);
  2948. }
  2949. }
  2950. else
  2951. {
  2952. // This should never happen as primitives are treated differently
  2953. asASSERT(false);
  2954. }
  2955. }
  2956. }
  2957. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  2958. {
  2959. // Temporary variables are assumed to be initialized
  2960. if( type->isTemporary ) return true;
  2961. // Verify that it is a variable
  2962. if( !type->isVariable ) return true;
  2963. // Find the variable
  2964. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  2965. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  2966. if( v == 0 ) return true;
  2967. if( v->isInitialized ) return true;
  2968. // Complex types don't need this test
  2969. if( v->type.IsObject() ) return true;
  2970. // Mark as initialized so that the user will not be bothered again
  2971. v->isInitialized = true;
  2972. // Write warning
  2973. asCString str;
  2974. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  2975. Warning(str.AddressOf(), node);
  2976. return false;
  2977. }
  2978. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  2979. {
  2980. // Check if the variable is initialized (if it indeed is a variable)
  2981. IsVariableInitialized(&ctx->type, node);
  2982. asCDataType to = ctx->type.dataType;
  2983. to.MakeReference(false);
  2984. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  2985. ProcessDeferredParams(ctx);
  2986. }
  2987. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, asSExprContext *lvalueExpr)
  2988. {
  2989. ProcessPropertyGetAccessor(rctx, node);
  2990. // Make sure the rvalue is initialized if it is a variable
  2991. IsVariableInitialized(&rctx->type, node);
  2992. if( lvalue->IsPrimitive() )
  2993. {
  2994. if( rctx->type.dataType.IsPrimitive() )
  2995. {
  2996. if( rctx->type.dataType.IsReference() )
  2997. {
  2998. // Cannot do implicit conversion of references so we first convert the reference to a variable
  2999. ConvertToVariableNotIn(rctx, lvalueExpr);
  3000. }
  3001. }
  3002. // Implicitly convert the value to the right type
  3003. asCArray<int> usedVars;
  3004. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(usedVars);
  3005. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV, true, &usedVars);
  3006. // Check data type
  3007. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3008. {
  3009. asCString str;
  3010. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3011. Error(str.AddressOf(), node);
  3012. rctx->type.SetDummy();
  3013. }
  3014. // Make sure the rvalue is a variable
  3015. if( !rctx->type.isVariable )
  3016. ConvertToVariableNotIn(rctx, lvalueExpr);
  3017. }
  3018. else
  3019. {
  3020. asCDataType to = *lvalue;
  3021. to.MakeReference(false);
  3022. // TODO: ImplicitConversion should know to do this by itself
  3023. // First convert to a handle which will to a reference cast
  3024. if( !lvalue->IsObjectHandle() &&
  3025. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3026. to.MakeHandle(true);
  3027. // Don't allow the implicit conversion to create an object
  3028. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  3029. if( !lvalue->IsObjectHandle() &&
  3030. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3031. {
  3032. // Then convert to a reference, which will validate the handle
  3033. to.MakeHandle(false);
  3034. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  3035. }
  3036. // Check data type
  3037. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3038. {
  3039. asCString str;
  3040. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3041. Error(str.AddressOf(), node);
  3042. }
  3043. else
  3044. {
  3045. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3046. if( lvalue->IsObject() )
  3047. asASSERT(!rctx->type.dataType.IsReference());
  3048. }
  3049. }
  3050. }
  3051. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3052. {
  3053. if( !type.isLValue ) return false;
  3054. if( type.dataType.IsReadOnly() ) return false;
  3055. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3056. return true;
  3057. }
  3058. void asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3059. {
  3060. if( lvalue->dataType.IsReadOnly() )
  3061. Error(TXT_REF_IS_READ_ONLY, node);
  3062. if( lvalue->dataType.IsPrimitive() )
  3063. {
  3064. if( lvalue->isVariable )
  3065. {
  3066. // Copy the value between the variables directly
  3067. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3068. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3069. else
  3070. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3071. // Mark variable as initialized
  3072. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3073. if( v ) v->isInitialized = true;
  3074. }
  3075. else if( lvalue->dataType.IsReference() )
  3076. {
  3077. // Copy the value of the variable to the reference in the register
  3078. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3079. if( s == 1 )
  3080. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3081. else if( s == 2 )
  3082. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3083. else if( s == 4 )
  3084. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3085. else if( s == 8 )
  3086. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3087. }
  3088. else
  3089. {
  3090. Error(TXT_NOT_VALID_LVALUE, node);
  3091. return;
  3092. }
  3093. }
  3094. else if( !lvalue->isExplicitHandle )
  3095. {
  3096. asSExprContext ctx(engine);
  3097. ctx.type = *lvalue;
  3098. Dereference(&ctx, true);
  3099. *lvalue = ctx.type;
  3100. bc->AddCode(&ctx.bc);
  3101. // TODO: Can't this leave deferred output params unhandled?
  3102. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3103. // The beh->copy member will be removed.
  3104. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3105. if( beh->copy )
  3106. {
  3107. // Call the copy operator
  3108. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  3109. bc->Instr(asBC_PshRPtr);
  3110. }
  3111. else
  3112. {
  3113. // Default copy operator
  3114. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3115. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3116. {
  3117. Error(TXT_NO_DEFAULT_COPY_OP, node);
  3118. }
  3119. // Copy larger data types from a reference
  3120. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3121. }
  3122. }
  3123. else
  3124. {
  3125. // TODO: The object handle can be stored in a variable as well
  3126. if( !lvalue->dataType.IsReference() )
  3127. {
  3128. Error(TXT_NOT_VALID_REFERENCE, node);
  3129. return;
  3130. }
  3131. // TODO: optimize: Convert to register based
  3132. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3133. // Mark variable as initialized
  3134. if( variables )
  3135. {
  3136. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3137. if( v ) v->isInitialized = true;
  3138. }
  3139. }
  3140. }
  3141. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3142. {
  3143. bool conversionDone = false;
  3144. // TODO: shared: Do not allow casting to non shared type
  3145. asCArray<int> ops;
  3146. asUINT n;
  3147. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3148. {
  3149. // We need it to be a reference
  3150. if( !ctx->type.dataType.IsReference() )
  3151. {
  3152. asCDataType to = ctx->type.dataType;
  3153. to.MakeReference(true);
  3154. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3155. }
  3156. if( isExplicit )
  3157. {
  3158. // Allow dynamic cast between object handles (only for script objects).
  3159. // At run time this may result in a null handle,
  3160. // which when used will throw an exception
  3161. conversionDone = true;
  3162. if( generateCode )
  3163. {
  3164. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3165. // Allocate a temporary variable for the returned object
  3166. int returnOffset = AllocateVariable(to, true);
  3167. // Move the pointer from the object register to the temporary variable
  3168. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3169. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3170. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3171. ctx->type.SetVariable(to, returnOffset, true);
  3172. ctx->type.dataType.MakeReference(true);
  3173. }
  3174. else
  3175. {
  3176. ctx->type.dataType = to;
  3177. ctx->type.dataType.MakeReference(true);
  3178. }
  3179. }
  3180. else
  3181. {
  3182. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3183. {
  3184. conversionDone = true;
  3185. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3186. }
  3187. }
  3188. }
  3189. else
  3190. {
  3191. // Find a suitable registered behaviour
  3192. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3193. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3194. {
  3195. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3196. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3197. {
  3198. int funcId = beh->operators[n+1];
  3199. // Is the operator for the output type?
  3200. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3201. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3202. continue;
  3203. ops.PushLast(funcId);
  3204. }
  3205. }
  3206. // It shouldn't be possible to have more than one
  3207. asASSERT( ops.GetLength() <= 1 );
  3208. // Should only have one behaviour for each output type
  3209. if( ops.GetLength() == 1 )
  3210. {
  3211. if( generateCode )
  3212. {
  3213. // TODO: optimize: Instead of producing bytecode for checking if the handle is
  3214. // null, we can create a special CALLSYS instruction that checks
  3215. // if the object pointer is null and if so sets the object register
  3216. // to null directly without executing the function.
  3217. //
  3218. // Alternatively I could force the ref cast behaviours be global
  3219. // functions with 1 parameter, even though they should still be
  3220. // registered with RegisterObjectBehaviour()
  3221. // Add code to avoid calling the cast behaviour if the handle is already null,
  3222. // because that will raise a null pointer exception due to the cast behaviour
  3223. // being a class method, and the this pointer cannot be null.
  3224. if( ctx->type.isVariable )
  3225. ctx->bc.Pop(AS_PTR_SIZE);
  3226. else
  3227. {
  3228. Dereference(ctx, true);
  3229. ConvertToVariable(ctx);
  3230. }
  3231. #ifdef AS_64BIT_PTR
  3232. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt64, false), true);
  3233. ctx->bc.InstrW_QW(asBC_SetV8, (asWORD)offset, 0);
  3234. ctx->bc.InstrW_W(asBC_CMPi64, ctx->type.stackOffset, offset);
  3235. DeallocateVariable(offset);
  3236. #else
  3237. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt, false), true);
  3238. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  3239. ctx->bc.InstrW_W(asBC_CMPi, ctx->type.stackOffset, offset);
  3240. DeallocateVariable(offset);
  3241. #endif
  3242. int afterLabel = nextLabel++;
  3243. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3244. // Call the cast operator
  3245. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3246. ctx->bc.Instr(asBC_RDSPTR);
  3247. ctx->type.dataType.MakeReference(false);
  3248. asCTypeInfo objType = ctx->type;
  3249. asCArray<asSExprContext *> args;
  3250. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3251. ctx->bc.Pop(AS_PTR_SIZE);
  3252. int endLabel = nextLabel++;
  3253. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3254. ctx->bc.Label((short)afterLabel);
  3255. // Make a NULL pointer
  3256. #ifdef AS_64BIT_PTR
  3257. ctx->bc.InstrW_QW(asBC_SetV8, ctx->type.stackOffset, 0);
  3258. #else
  3259. ctx->bc.InstrW_DW(asBC_SetV4, ctx->type.stackOffset, 0);
  3260. #endif
  3261. ctx->bc.Label((short)endLabel);
  3262. // Since we're receiving a handle, we can release the original variable
  3263. ReleaseTemporaryVariable(objType, &ctx->bc);
  3264. // Push the reference to the handle on the stack
  3265. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3266. }
  3267. else
  3268. {
  3269. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3270. ctx->type.Set(func->returnType);
  3271. }
  3272. }
  3273. else if( ops.GetLength() == 0 )
  3274. {
  3275. // Check for the generic ref cast behaviour
  3276. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3277. {
  3278. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3279. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3280. {
  3281. int funcId = beh->operators[n+1];
  3282. // Does the operator take the ?&out parameter?
  3283. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3284. if( func->parameterTypes.GetLength() != 1 ||
  3285. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3286. func->inOutFlags[0] != asTM_OUTREF )
  3287. continue;
  3288. ops.PushLast(funcId);
  3289. }
  3290. }
  3291. // It shouldn't be possible to have more than one
  3292. asASSERT( ops.GetLength() <= 1 );
  3293. if( ops.GetLength() == 1 )
  3294. {
  3295. if( generateCode )
  3296. {
  3297. asASSERT(to.IsObjectHandle());
  3298. // Allocate a temporary variable of the requested handle type
  3299. asCArray<int> vars;
  3300. ctx->bc.GetVarsUsed(vars);
  3301. int stackOffset = AllocateVariableNotIn(to, true, &vars);
  3302. // Pass the reference of that variable to the function as output parameter
  3303. asCDataType toRef(to);
  3304. toRef.MakeReference(true);
  3305. asCArray<asSExprContext *> args;
  3306. asSExprContext arg(engine);
  3307. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3308. // Don't mark the variable as temporary, so it won't be freed too early
  3309. arg.type.SetVariable(toRef, stackOffset, false);
  3310. arg.type.isLValue = true;
  3311. arg.type.isExplicitHandle = true;
  3312. args.PushLast(&arg);
  3313. // Call the behaviour method
  3314. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  3315. // Use the reference to the variable as the result of the expression
  3316. // Now we can mark the variable as temporary
  3317. ctx->type.SetVariable(toRef, stackOffset, true);
  3318. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3319. }
  3320. else
  3321. {
  3322. // All casts are legal
  3323. ctx->type.Set(to);
  3324. }
  3325. }
  3326. }
  3327. }
  3328. return conversionDone;
  3329. }
  3330. void asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3331. {
  3332. asCDataType to = toOrig;
  3333. to.MakeReference(false);
  3334. asASSERT( !ctx->type.dataType.IsReference() );
  3335. // Start by implicitly converting constant values
  3336. if( ctx->type.isConstant )
  3337. ImplicitConversionConstant(ctx, to, node, convType);
  3338. // A primitive is const or not
  3339. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3340. if( to == ctx->type.dataType )
  3341. return;
  3342. // Allow implicit conversion between numbers
  3343. if( generateCode )
  3344. {
  3345. // Convert smaller types to 32bit first
  3346. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3347. if( s < 4 )
  3348. {
  3349. ConvertToTempVariableNotIn(ctx, reservedVars);
  3350. if( ctx->type.dataType.IsIntegerType() )
  3351. {
  3352. if( s == 1 )
  3353. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3354. else if( s == 2 )
  3355. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3356. ctx->type.dataType.SetTokenType(ttInt);
  3357. }
  3358. else if( ctx->type.dataType.IsUnsignedType() )
  3359. {
  3360. if( s == 1 )
  3361. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3362. else if( s == 2 )
  3363. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3364. ctx->type.dataType.SetTokenType(ttUInt);
  3365. }
  3366. }
  3367. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3368. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3369. {
  3370. if( ctx->type.dataType.IsIntegerType() ||
  3371. ctx->type.dataType.IsUnsignedType() ||
  3372. ctx->type.dataType.IsEnumType() )
  3373. {
  3374. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3375. {
  3376. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3377. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3378. }
  3379. else
  3380. {
  3381. ConvertToTempVariableNotIn(ctx, reservedVars);
  3382. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3383. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3384. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3385. ctx->type.SetVariable(to, offset, true);
  3386. }
  3387. }
  3388. else if( ctx->type.dataType.IsFloatType() )
  3389. {
  3390. ConvertToTempVariableNotIn(ctx, reservedVars);
  3391. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3392. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3393. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3394. }
  3395. else if( ctx->type.dataType.IsDoubleType() )
  3396. {
  3397. ConvertToTempVariableNotIn(ctx, reservedVars);
  3398. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3399. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3400. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3401. ctx->type.SetVariable(to, offset, true);
  3402. }
  3403. // Convert to smaller integer if necessary
  3404. int s = to.GetSizeInMemoryBytes();
  3405. if( s < 4 )
  3406. {
  3407. ConvertToTempVariableNotIn(ctx, reservedVars);
  3408. if( s == 1 )
  3409. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3410. else if( s == 2 )
  3411. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3412. }
  3413. }
  3414. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3415. {
  3416. if( ctx->type.dataType.IsIntegerType() ||
  3417. ctx->type.dataType.IsUnsignedType() ||
  3418. ctx->type.dataType.IsEnumType() )
  3419. {
  3420. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3421. {
  3422. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3423. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3424. }
  3425. else
  3426. {
  3427. ConvertToTempVariableNotIn(ctx, reservedVars);
  3428. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3429. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3430. if( ctx->type.dataType.IsUnsignedType() )
  3431. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3432. else
  3433. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3434. ctx->type.SetVariable(to, offset, true);
  3435. }
  3436. }
  3437. else if( ctx->type.dataType.IsFloatType() )
  3438. {
  3439. ConvertToTempVariableNotIn(ctx, reservedVars);
  3440. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3441. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3442. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3443. ctx->type.SetVariable(to, offset, true);
  3444. }
  3445. else if( ctx->type.dataType.IsDoubleType() )
  3446. {
  3447. ConvertToTempVariableNotIn(ctx, reservedVars);
  3448. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3449. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3450. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3451. }
  3452. }
  3453. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3454. {
  3455. if( ctx->type.dataType.IsIntegerType() ||
  3456. ctx->type.dataType.IsUnsignedType() ||
  3457. ctx->type.dataType.IsEnumType() )
  3458. {
  3459. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3460. {
  3461. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3462. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3463. }
  3464. else
  3465. {
  3466. ConvertToTempVariableNotIn(ctx, reservedVars);
  3467. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3468. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3469. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3470. ctx->type.SetVariable(to, offset, true);
  3471. }
  3472. }
  3473. else if( ctx->type.dataType.IsFloatType() )
  3474. {
  3475. ConvertToTempVariableNotIn(ctx, reservedVars);
  3476. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3477. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3478. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3479. }
  3480. else if( ctx->type.dataType.IsDoubleType() )
  3481. {
  3482. ConvertToTempVariableNotIn(ctx, reservedVars);
  3483. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3484. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3485. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3486. ctx->type.SetVariable(to, offset, true);
  3487. }
  3488. // Convert to smaller integer if necessary
  3489. int s = to.GetSizeInMemoryBytes();
  3490. if( s < 4 )
  3491. {
  3492. ConvertToTempVariableNotIn(ctx, reservedVars);
  3493. if( s == 1 )
  3494. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3495. else if( s == 2 )
  3496. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3497. }
  3498. }
  3499. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3500. {
  3501. if( ctx->type.dataType.IsIntegerType() ||
  3502. ctx->type.dataType.IsUnsignedType() ||
  3503. ctx->type.dataType.IsEnumType() )
  3504. {
  3505. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3506. {
  3507. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3508. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3509. }
  3510. else
  3511. {
  3512. ConvertToTempVariableNotIn(ctx, reservedVars);
  3513. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3514. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3515. if( ctx->type.dataType.IsUnsignedType() )
  3516. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3517. else
  3518. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3519. ctx->type.SetVariable(to, offset, true);
  3520. }
  3521. }
  3522. else if( ctx->type.dataType.IsFloatType() )
  3523. {
  3524. ConvertToTempVariableNotIn(ctx, reservedVars);
  3525. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3526. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3527. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3528. ctx->type.SetVariable(to, offset, true);
  3529. }
  3530. else if( ctx->type.dataType.IsDoubleType() )
  3531. {
  3532. ConvertToTempVariableNotIn(ctx, reservedVars);
  3533. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3534. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3535. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3536. }
  3537. }
  3538. else if( to.IsFloatType() )
  3539. {
  3540. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3541. {
  3542. ConvertToTempVariableNotIn(ctx, reservedVars);
  3543. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3544. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3545. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3546. }
  3547. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3548. {
  3549. ConvertToTempVariableNotIn(ctx, reservedVars);
  3550. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3551. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3552. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  3553. ctx->type.SetVariable(to, offset, true);
  3554. }
  3555. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3556. {
  3557. ConvertToTempVariableNotIn(ctx, reservedVars);
  3558. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  3559. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3560. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3561. }
  3562. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3563. {
  3564. ConvertToTempVariableNotIn(ctx, reservedVars);
  3565. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3566. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3567. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  3568. ctx->type.SetVariable(to, offset, true);
  3569. }
  3570. else if( ctx->type.dataType.IsDoubleType() )
  3571. {
  3572. ConvertToTempVariableNotIn(ctx, reservedVars);
  3573. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3574. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3575. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  3576. ctx->type.SetVariable(to, offset, true);
  3577. }
  3578. }
  3579. else if( to.IsDoubleType() )
  3580. {
  3581. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3582. {
  3583. ConvertToTempVariableNotIn(ctx, reservedVars);
  3584. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3585. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3586. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  3587. ctx->type.SetVariable(to, offset, true);
  3588. }
  3589. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3590. {
  3591. ConvertToTempVariableNotIn(ctx, reservedVars);
  3592. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  3593. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3594. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3595. }
  3596. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3597. {
  3598. ConvertToTempVariableNotIn(ctx, reservedVars);
  3599. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3600. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3601. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  3602. ctx->type.SetVariable(to, offset, true);
  3603. }
  3604. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3605. {
  3606. ConvertToTempVariableNotIn(ctx, reservedVars);
  3607. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  3608. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3609. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3610. }
  3611. else if( ctx->type.dataType.IsFloatType() )
  3612. {
  3613. ConvertToTempVariableNotIn(ctx, reservedVars);
  3614. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3615. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3616. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  3617. ctx->type.SetVariable(to, offset, true);
  3618. }
  3619. }
  3620. }
  3621. else
  3622. {
  3623. if( (to.IsIntegerType() || to.IsUnsignedType() ||
  3624. to.IsFloatType() || to.IsDoubleType() ||
  3625. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  3626. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  3627. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
  3628. ctx->type.dataType.IsEnumType()) )
  3629. {
  3630. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3631. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3632. }
  3633. }
  3634. // Primitive types on the stack, can be const or non-const
  3635. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3636. }
  3637. void asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3638. {
  3639. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  3640. ctx->type.dataType.IsNullHandle() );
  3641. // No conversion from void to any other type
  3642. if( ctx->type.dataType.GetTokenType() == ttVoid )
  3643. return;
  3644. // Do we want a var type?
  3645. if( to.GetTokenType() == ttQuestion )
  3646. {
  3647. // Any type can be converted to a var type, but only when not generating code
  3648. asASSERT( !generateCode );
  3649. ctx->type.dataType = to;
  3650. return;
  3651. }
  3652. // Do we want a primitive?
  3653. else if( to.IsPrimitive() )
  3654. {
  3655. if( !ctx->type.dataType.IsPrimitive() )
  3656. ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3657. else
  3658. ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3659. }
  3660. else // The target is a complex type
  3661. {
  3662. if( ctx->type.dataType.IsPrimitive() )
  3663. ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3664. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  3665. ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3666. }
  3667. }
  3668. void asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3669. {
  3670. if( ctx->type.isExplicitHandle )
  3671. {
  3672. // An explicit handle cannot be converted to a primitive
  3673. if( convType != asIC_IMPLICIT_CONV && node )
  3674. {
  3675. asCString str;
  3676. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3677. Error(str.AddressOf(), node);
  3678. }
  3679. return;
  3680. }
  3681. // TODO: Must use the const cast behaviour if the object is read-only
  3682. // Find matching value cast behaviours
  3683. // Here we're only interested in those that convert the type to a primitive type
  3684. asCArray<int> funcs;
  3685. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3686. if( beh )
  3687. {
  3688. if( convType == asIC_EXPLICIT_VAL_CAST )
  3689. {
  3690. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3691. {
  3692. // accept both implicit and explicit cast
  3693. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3694. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3695. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3696. funcs.PushLast(beh->operators[n+1]);
  3697. }
  3698. }
  3699. else
  3700. {
  3701. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3702. {
  3703. // accept only implicit cast
  3704. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3705. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3706. funcs.PushLast(beh->operators[n+1]);
  3707. }
  3708. }
  3709. }
  3710. // This matrix describes the priorities of the types to search for, for each target type
  3711. // The first column is the target type, the priorities goes from left to right
  3712. eTokenType matchMtx[10][10] =
  3713. {
  3714. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3715. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3716. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3717. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3718. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3719. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3720. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  3721. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  3722. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  3723. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  3724. };
  3725. // Which row to use?
  3726. eTokenType *row = 0;
  3727. for( unsigned int type = 0; type < 10; type++ )
  3728. {
  3729. if( to.GetTokenType() == matchMtx[type][0] )
  3730. {
  3731. row = &matchMtx[type][0];
  3732. break;
  3733. }
  3734. }
  3735. // Find the best matching cast operator
  3736. int funcId = 0;
  3737. if( row )
  3738. {
  3739. asCDataType target(to);
  3740. // Priority goes from left to right in the matrix
  3741. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  3742. {
  3743. target.SetTokenType(row[attempt]);
  3744. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3745. {
  3746. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  3747. if( descr->returnType.IsEqualExceptConst(target) )
  3748. {
  3749. funcId = funcs[n];
  3750. break;
  3751. }
  3752. }
  3753. }
  3754. }
  3755. // Did we find a suitable function?
  3756. if( funcId != 0 )
  3757. {
  3758. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  3759. if( generateCode )
  3760. {
  3761. asCTypeInfo objType = ctx->type;
  3762. Dereference(ctx, true);
  3763. PerformFunctionCall(funcId, ctx);
  3764. ReleaseTemporaryVariable(objType, &ctx->bc);
  3765. }
  3766. else
  3767. ctx->type.Set(descr->returnType);
  3768. // Allow one more implicit conversion to another primitive type
  3769. ImplicitConversion(ctx, to, node, convType, generateCode, reservedVars, false);
  3770. }
  3771. else
  3772. {
  3773. if( convType != asIC_IMPLICIT_CONV && node )
  3774. {
  3775. asCString str;
  3776. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3777. Error(str.AddressOf(), node);
  3778. }
  3779. }
  3780. }
  3781. void asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3782. {
  3783. // Convert null to any object type handle, but not to a non-handle type
  3784. if( ctx->type.IsNullConstant() )
  3785. {
  3786. if( to.IsObjectHandle() )
  3787. ctx->type.dataType = to;
  3788. return;
  3789. }
  3790. asASSERT(ctx->type.dataType.GetObjectType());
  3791. // First attempt to convert the base type without instanciating another instance
  3792. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3793. {
  3794. // If the to type is an interface and the from type implements it, then we can convert it immediately
  3795. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  3796. {
  3797. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3798. }
  3799. // If the to type is a class and the from type derives from it, then we can convert it immediately
  3800. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3801. {
  3802. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3803. }
  3804. // If the types are not equal yet, then we may still be able to find a reference cast
  3805. if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  3806. {
  3807. // A ref cast must not remove the constness
  3808. bool isConst = false;
  3809. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  3810. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  3811. isConst = true;
  3812. // We may still be able to find an implicit ref cast behaviour
  3813. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  3814. ctx->type.dataType.MakeHandleToConst(isConst);
  3815. }
  3816. }
  3817. // If the base type is still different, and we are allowed to instance
  3818. // another object then we can try an implicit value cast
  3819. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  3820. {
  3821. // TODO: Implement support for implicit constructor/factory
  3822. asCArray<int> funcs;
  3823. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3824. if( beh )
  3825. {
  3826. if( convType == asIC_EXPLICIT_VAL_CAST )
  3827. {
  3828. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3829. {
  3830. // accept both implicit and explicit cast
  3831. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3832. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3833. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3834. funcs.PushLast(beh->operators[n+1]);
  3835. }
  3836. }
  3837. else
  3838. {
  3839. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3840. {
  3841. // accept only implicit cast
  3842. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3843. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3844. funcs.PushLast(beh->operators[n+1]);
  3845. }
  3846. }
  3847. }
  3848. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  3849. asASSERT( funcs.GetLength() <= 1 );
  3850. if( funcs.GetLength() == 1 )
  3851. {
  3852. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  3853. if( generateCode )
  3854. {
  3855. asCTypeInfo objType = ctx->type;
  3856. Dereference(ctx, true);
  3857. bool useVariable = false;
  3858. int stackOffset = 0;
  3859. #ifndef AS_OLD
  3860. if( f->DoesReturnOnStack() )
  3861. {
  3862. useVariable = true;
  3863. stackOffset = AllocateVariable(f->returnType, true);
  3864. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  3865. }
  3866. #endif
  3867. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  3868. ReleaseTemporaryVariable(objType, &ctx->bc);
  3869. }
  3870. else
  3871. ctx->type.Set(f->returnType);
  3872. }
  3873. }
  3874. // If we still haven't converted the base type to the correct type, then there is no need to continue
  3875. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3876. return;
  3877. // Convert matching function types
  3878. if( to.GetFuncDef() && ctx->type.dataType.GetFuncDef() &&
  3879. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  3880. {
  3881. asCScriptFunction *toFunc = to.GetFuncDef();
  3882. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  3883. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  3884. {
  3885. ctx->type.dataType.SetFuncDef(toFunc);
  3886. }
  3887. }
  3888. if( to.IsObjectHandle() )
  3889. {
  3890. // reference to handle -> handle
  3891. // reference -> handle
  3892. // object -> handle
  3893. // handle -> reference to handle
  3894. // reference -> reference to handle
  3895. // object -> reference to handle
  3896. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  3897. // If the rvalue is a handle to a const object, then
  3898. // the lvalue must also be a handle to a const object
  3899. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  3900. {
  3901. if( convType != asIC_IMPLICIT_CONV )
  3902. {
  3903. asASSERT(node);
  3904. asCString str;
  3905. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3906. Error(str.AddressOf(), node);
  3907. }
  3908. }
  3909. if( !ctx->type.dataType.IsObjectHandle() )
  3910. {
  3911. // An object type can be directly converted to a handle of the same type
  3912. if( ctx->type.dataType.SupportHandles() )
  3913. {
  3914. ctx->type.dataType.MakeHandle(true);
  3915. }
  3916. if( ctx->type.dataType.IsObjectHandle() )
  3917. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3918. if( to.IsHandleToConst() && ctx->type.dataType.IsObjectHandle() )
  3919. ctx->type.dataType.MakeHandleToConst(true);
  3920. }
  3921. else
  3922. {
  3923. // A handle to non-const can be converted to a
  3924. // handle to const, but not the other way
  3925. if( to.IsHandleToConst() )
  3926. ctx->type.dataType.MakeHandleToConst(true);
  3927. // A const handle can be converted to a non-const
  3928. // handle and vice versa as the handle is just a value
  3929. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3930. }
  3931. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  3932. {
  3933. if( generateCode )
  3934. {
  3935. // If the input type is a handle, then a simple ref copy is enough
  3936. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3937. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  3938. // If the input type is read-only we'll need to temporarily
  3939. // remove this constness, otherwise the assignment will fail
  3940. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  3941. ctx->type.dataType.MakeReadOnly(false);
  3942. // If the object already is a temporary variable, then the copy
  3943. // doesn't have to be made as it is already a unique object
  3944. PrepareTemporaryObject(node, ctx, reservedVars);
  3945. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  3946. ctx->type.isExplicitHandle = isExplicitHandle;
  3947. }
  3948. // A non-reference can be converted to a reference,
  3949. // by putting the value in a temporary variable
  3950. ctx->type.dataType.MakeReference(true);
  3951. // Since it is a new temporary variable it doesn't have to be const
  3952. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3953. }
  3954. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  3955. {
  3956. // ASHANDLE is really a value type, even though it looks
  3957. // like a handle, so we shouldn't dereference it
  3958. if( !(ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  3959. (ctx->type.isVariable && IsVariableOnHeap(ctx->type.stackOffset)) )
  3960. Dereference(ctx, generateCode);
  3961. else
  3962. ctx->type.dataType.MakeReference(false);
  3963. }
  3964. }
  3965. else
  3966. {
  3967. if( !to.IsReference() )
  3968. {
  3969. // reference to handle -> object
  3970. // handle -> object
  3971. // reference -> object
  3972. // An implicit handle can be converted to an object by adding a check for null pointer
  3973. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  3974. {
  3975. if( generateCode )
  3976. ctx->bc.Instr(asBC_CHKREF);
  3977. ctx->type.dataType.MakeHandle(false);
  3978. }
  3979. // A const object can be converted to a non-const object through a copy
  3980. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  3981. allowObjectConstruct )
  3982. {
  3983. // Does the object type allow a copy to be made?
  3984. if( ctx->type.dataType.CanBeCopied() )
  3985. {
  3986. if( generateCode )
  3987. {
  3988. // Make a temporary object with the copy
  3989. PrepareTemporaryObject(node, ctx, reservedVars);
  3990. }
  3991. // In case the object was already in a temporary variable, then the function
  3992. // didn't really do anything so we need to remove the constness here
  3993. ctx->type.dataType.MakeReadOnly(false);
  3994. }
  3995. }
  3996. if( ctx->type.dataType.IsReference() )
  3997. {
  3998. Dereference(ctx, generateCode);
  3999. // TODO: Can't this leave unhandled deferred output params?
  4000. }
  4001. // A non-const object can be converted to a const object directly
  4002. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4003. {
  4004. ctx->type.dataType.MakeReadOnly(true);
  4005. }
  4006. }
  4007. else
  4008. {
  4009. // reference to handle -> reference
  4010. // handle -> reference
  4011. // object -> reference
  4012. if( ctx->type.dataType.IsReference() )
  4013. {
  4014. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4015. {
  4016. // ASHANDLE objects are really value types, so explicit handle can be removed
  4017. ctx->type.isExplicitHandle = false;
  4018. ctx->type.dataType.MakeHandle(false);
  4019. }
  4020. // A reference to a handle can be converted to a reference to an object
  4021. // by first reading the address, then verifying that it is not null
  4022. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4023. {
  4024. ctx->type.dataType.MakeHandle(false);
  4025. if( generateCode )
  4026. ctx->bc.Instr(asBC_ChkRefS);
  4027. }
  4028. // A reference to a non-const can be converted to a reference to a const
  4029. if( to.IsReadOnly() )
  4030. ctx->type.dataType.MakeReadOnly(true);
  4031. else if( ctx->type.dataType.IsReadOnly() )
  4032. {
  4033. // A reference to a const can be converted to a reference to a
  4034. // non-const by copying the object to a temporary variable
  4035. ctx->type.dataType.MakeReadOnly(false);
  4036. if( generateCode )
  4037. {
  4038. // If the object already is a temporary variable, then the copy
  4039. // doesn't have to be made as it is already a unique object
  4040. PrepareTemporaryObject(node, ctx, reservedVars);
  4041. }
  4042. }
  4043. }
  4044. else
  4045. {
  4046. // A value type allocated on the stack is differentiated
  4047. // by it not being a reference. But it can be handled as
  4048. // reference by pushing the pointer on the stack
  4049. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  4050. (ctx->type.isVariable || ctx->type.isTemporary) &&
  4051. !IsVariableOnHeap(ctx->type.stackOffset) )
  4052. {
  4053. // Actually the pointer is already pushed on the stack in
  4054. // CompileVariableAccess, so we don't need to do anything else
  4055. }
  4056. else if( generateCode )
  4057. {
  4058. // A non-reference can be converted to a reference,
  4059. // by putting the value in a temporary variable
  4060. // If the input type is read-only we'll need to temporarily
  4061. // remove this constness, otherwise the assignment will fail
  4062. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4063. ctx->type.dataType.MakeReadOnly(false);
  4064. // If the object already is a temporary variable, then the copy
  4065. // doesn't have to be made as it is already a unique object
  4066. PrepareTemporaryObject(node, ctx, reservedVars);
  4067. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4068. }
  4069. // A handle can be converted to a reference, by checking for a null pointer
  4070. if( ctx->type.dataType.IsObjectHandle() )
  4071. {
  4072. if( generateCode )
  4073. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4074. ctx->type.dataType.MakeHandle(false);
  4075. ctx->type.dataType.MakeReference(true);
  4076. // TODO: Make sure a handle to const isn't converted to non-const reference
  4077. }
  4078. else
  4079. {
  4080. // This may look strange as the conversion was to make the expression a reference
  4081. // but a value type allocated on the stack is a reference even without the type
  4082. // being marked as such.
  4083. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4084. }
  4085. // TODO: If the variable is an object allocated on the stack, this is not true
  4086. // Since it is a new temporary variable it doesn't have to be const
  4087. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4088. }
  4089. }
  4090. }
  4091. }
  4092. void asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, asCArray<int> * /*reservedVars*/, bool /*allowObjectConstruct*/)
  4093. {
  4094. // TODO: This function should call the constructor/factory that has been marked as available
  4095. // for implicit conversions. The code will likely be similar to CallCopyConstructor()
  4096. }
  4097. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  4098. {
  4099. asASSERT(from->type.isConstant);
  4100. // TODO: node should be the node of the value that is
  4101. // converted (not the operator that provokes the implicit
  4102. // conversion)
  4103. // If the base type is correct there is no more to do
  4104. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  4105. // References cannot be constants
  4106. if( from->type.dataType.IsReference() ) return;
  4107. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  4108. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4109. {
  4110. if( from->type.dataType.IsFloatType() ||
  4111. from->type.dataType.IsDoubleType() ||
  4112. from->type.dataType.IsUnsignedType() ||
  4113. from->type.dataType.IsIntegerType() ||
  4114. from->type.dataType.IsEnumType() )
  4115. {
  4116. // Transform the value
  4117. // Float constants can be implicitly converted to int
  4118. if( from->type.dataType.IsFloatType() )
  4119. {
  4120. float fc = from->type.floatValue;
  4121. int ic = int(fc);
  4122. if( float(ic) != fc )
  4123. {
  4124. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4125. }
  4126. from->type.intValue = ic;
  4127. }
  4128. // Double constants can be implicitly converted to int
  4129. else if( from->type.dataType.IsDoubleType() )
  4130. {
  4131. double fc = from->type.doubleValue;
  4132. int ic = int(fc);
  4133. if( double(ic) != fc )
  4134. {
  4135. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4136. }
  4137. from->type.intValue = ic;
  4138. }
  4139. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4140. {
  4141. // Verify that it is possible to convert to signed without getting negative
  4142. if( from->type.intValue < 0 )
  4143. {
  4144. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4145. }
  4146. // Convert to 32bit
  4147. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4148. from->type.intValue = from->type.byteValue;
  4149. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4150. from->type.intValue = from->type.wordValue;
  4151. }
  4152. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4153. {
  4154. // Convert to 32bit
  4155. from->type.intValue = int(from->type.qwordValue);
  4156. }
  4157. else if( from->type.dataType.IsIntegerType() &&
  4158. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4159. {
  4160. // Convert to 32bit
  4161. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4162. from->type.intValue = (signed char)from->type.byteValue;
  4163. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4164. from->type.intValue = (short)from->type.wordValue;
  4165. }
  4166. else if( from->type.dataType.IsEnumType() )
  4167. {
  4168. // Enum type is already an integer type
  4169. }
  4170. // Set the resulting type
  4171. if( to.IsEnumType() )
  4172. from->type.dataType = to;
  4173. else
  4174. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4175. }
  4176. // Check if a downsize is necessary
  4177. if( to.IsIntegerType() &&
  4178. from->type.dataType.IsIntegerType() &&
  4179. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4180. {
  4181. // Verify if it is possible
  4182. if( to.GetSizeInMemoryBytes() == 1 )
  4183. {
  4184. if( char(from->type.intValue) != from->type.intValue )
  4185. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4186. from->type.byteValue = char(from->type.intValue);
  4187. }
  4188. else if( to.GetSizeInMemoryBytes() == 2 )
  4189. {
  4190. if( short(from->type.intValue) != from->type.intValue )
  4191. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4192. from->type.wordValue = short(from->type.intValue);
  4193. }
  4194. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4195. }
  4196. }
  4197. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4198. {
  4199. // Float constants can be implicitly converted to int
  4200. if( from->type.dataType.IsFloatType() )
  4201. {
  4202. float fc = from->type.floatValue;
  4203. asINT64 ic = asINT64(fc);
  4204. if( float(ic) != fc )
  4205. {
  4206. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4207. }
  4208. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4209. from->type.qwordValue = ic;
  4210. }
  4211. // Double constants can be implicitly converted to int
  4212. else if( from->type.dataType.IsDoubleType() )
  4213. {
  4214. double fc = from->type.doubleValue;
  4215. asINT64 ic = asINT64(fc);
  4216. if( double(ic) != fc )
  4217. {
  4218. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4219. }
  4220. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4221. from->type.qwordValue = ic;
  4222. }
  4223. else if( from->type.dataType.IsUnsignedType() )
  4224. {
  4225. // Convert to 64bit
  4226. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4227. from->type.qwordValue = from->type.byteValue;
  4228. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4229. from->type.qwordValue = from->type.wordValue;
  4230. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4231. from->type.qwordValue = from->type.dwordValue;
  4232. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  4233. {
  4234. if( asINT64(from->type.qwordValue) < 0 )
  4235. {
  4236. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4237. }
  4238. }
  4239. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4240. }
  4241. else if( from->type.dataType.IsEnumType() )
  4242. {
  4243. from->type.qwordValue = from->type.intValue;
  4244. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4245. }
  4246. else if( from->type.dataType.IsIntegerType() )
  4247. {
  4248. // Convert to 64bit
  4249. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4250. from->type.qwordValue = (signed char)from->type.byteValue;
  4251. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4252. from->type.qwordValue = (short)from->type.wordValue;
  4253. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4254. from->type.qwordValue = from->type.intValue;
  4255. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4256. }
  4257. }
  4258. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4259. {
  4260. if( from->type.dataType.IsFloatType() )
  4261. {
  4262. float fc = from->type.floatValue;
  4263. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  4264. // To maintain a consistent behaviour across compilers we convert to int first.
  4265. asUINT uic = asUINT(int(fc));
  4266. if( float(uic) != fc )
  4267. {
  4268. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4269. }
  4270. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4271. from->type.intValue = uic;
  4272. // Try once more, in case of a smaller type
  4273. ImplicitConversionConstant(from, to, node, convType);
  4274. }
  4275. else if( from->type.dataType.IsDoubleType() )
  4276. {
  4277. double fc = from->type.doubleValue;
  4278. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  4279. // To maintain a consistent behaviour across compilers we convert to int first.
  4280. asUINT uic = asUINT(int(fc));
  4281. if( double(uic) != fc )
  4282. {
  4283. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4284. }
  4285. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4286. from->type.intValue = uic;
  4287. // Try once more, in case of a smaller type
  4288. ImplicitConversionConstant(from, to, node, convType);
  4289. }
  4290. else if( from->type.dataType.IsEnumType() )
  4291. {
  4292. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4293. // Try once more, in case of a smaller type
  4294. ImplicitConversionConstant(from, to, node, convType);
  4295. }
  4296. else if( from->type.dataType.IsIntegerType() )
  4297. {
  4298. // Verify that it is possible to convert to unsigned without loosing negative
  4299. if( from->type.intValue < 0 )
  4300. {
  4301. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4302. }
  4303. // Convert to 32bit
  4304. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4305. from->type.intValue = (signed char)from->type.byteValue;
  4306. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4307. from->type.intValue = (short)from->type.wordValue;
  4308. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4309. // Try once more, in case of a smaller type
  4310. ImplicitConversionConstant(from, to, node, convType);
  4311. }
  4312. else if( from->type.dataType.IsUnsignedType() &&
  4313. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4314. {
  4315. // Convert to 32bit
  4316. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4317. from->type.dwordValue = from->type.byteValue;
  4318. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4319. from->type.dwordValue = from->type.wordValue;
  4320. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4321. // Try once more, in case of a smaller type
  4322. ImplicitConversionConstant(from, to, node, convType);
  4323. }
  4324. else if( from->type.dataType.IsUnsignedType() &&
  4325. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4326. {
  4327. // Verify if it is possible
  4328. if( to.GetSizeInMemoryBytes() == 1 )
  4329. {
  4330. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  4331. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4332. from->type.byteValue = asBYTE(from->type.dwordValue);
  4333. }
  4334. else if( to.GetSizeInMemoryBytes() == 2 )
  4335. {
  4336. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  4337. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4338. from->type.wordValue = asWORD(from->type.dwordValue);
  4339. }
  4340. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4341. }
  4342. }
  4343. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4344. {
  4345. if( from->type.dataType.IsFloatType() )
  4346. {
  4347. float fc = from->type.floatValue;
  4348. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4349. asQWORD uic = asQWORD(asINT64(fc));
  4350. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4351. // MSVC6 doesn't support this conversion
  4352. if( float(uic) != fc )
  4353. {
  4354. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4355. }
  4356. #endif
  4357. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4358. from->type.qwordValue = uic;
  4359. }
  4360. else if( from->type.dataType.IsDoubleType() )
  4361. {
  4362. double fc = from->type.doubleValue;
  4363. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4364. asQWORD uic = asQWORD(asINT64(fc));
  4365. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4366. // MSVC6 doesn't support this conversion
  4367. if( double(uic) != fc )
  4368. {
  4369. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4370. }
  4371. #endif
  4372. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4373. from->type.qwordValue = uic;
  4374. }
  4375. else if( from->type.dataType.IsEnumType() )
  4376. {
  4377. from->type.qwordValue = (asINT64)from->type.intValue;
  4378. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4379. }
  4380. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4381. {
  4382. // Convert to 64bit
  4383. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4384. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  4385. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4386. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  4387. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4388. from->type.qwordValue = (asINT64)from->type.intValue;
  4389. // Verify that it is possible to convert to unsigned without loosing negative
  4390. if( asINT64(from->type.qwordValue) < 0 )
  4391. {
  4392. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4393. }
  4394. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4395. }
  4396. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4397. {
  4398. // Verify that it is possible to convert to unsigned without loosing negative
  4399. if( asINT64(from->type.qwordValue) < 0 )
  4400. {
  4401. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4402. }
  4403. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4404. }
  4405. else if( from->type.dataType.IsUnsignedType() )
  4406. {
  4407. // Convert to 64bit
  4408. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4409. from->type.qwordValue = from->type.byteValue;
  4410. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4411. from->type.qwordValue = from->type.wordValue;
  4412. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4413. from->type.qwordValue = from->type.dwordValue;
  4414. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4415. }
  4416. }
  4417. else if( to.IsFloatType() )
  4418. {
  4419. if( from->type.dataType.IsDoubleType() )
  4420. {
  4421. double ic = from->type.doubleValue;
  4422. float fc = float(ic);
  4423. // Don't bother warning about this
  4424. // if( double(fc) != ic )
  4425. // {
  4426. // asCString str;
  4427. // str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  4428. // if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str.AddressOf(), node);
  4429. // }
  4430. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4431. from->type.floatValue = fc;
  4432. }
  4433. else if( from->type.dataType.IsEnumType() )
  4434. {
  4435. float fc = float(from->type.intValue);
  4436. if( int(fc) != from->type.intValue )
  4437. {
  4438. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4439. }
  4440. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4441. from->type.floatValue = fc;
  4442. }
  4443. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4444. {
  4445. // Must properly convert value in case the from value is smaller
  4446. int ic;
  4447. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4448. ic = (signed char)from->type.byteValue;
  4449. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4450. ic = (short)from->type.wordValue;
  4451. else
  4452. ic = from->type.intValue;
  4453. float fc = float(ic);
  4454. if( int(fc) != ic )
  4455. {
  4456. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4457. }
  4458. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4459. from->type.floatValue = fc;
  4460. }
  4461. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4462. {
  4463. float fc = float(asINT64(from->type.qwordValue));
  4464. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4465. {
  4466. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4467. }
  4468. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4469. from->type.floatValue = fc;
  4470. }
  4471. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4472. {
  4473. // Must properly convert value in case the from value is smaller
  4474. unsigned int uic;
  4475. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4476. uic = from->type.byteValue;
  4477. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4478. uic = from->type.wordValue;
  4479. else
  4480. uic = from->type.dwordValue;
  4481. float fc = float(uic);
  4482. if( (unsigned int)(fc) != uic )
  4483. {
  4484. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4485. }
  4486. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4487. from->type.floatValue = fc;
  4488. }
  4489. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4490. {
  4491. float fc = float((asINT64)from->type.qwordValue);
  4492. if( asQWORD(fc) != from->type.qwordValue )
  4493. {
  4494. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4495. }
  4496. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4497. from->type.floatValue = fc;
  4498. }
  4499. }
  4500. else if( to.IsDoubleType() )
  4501. {
  4502. if( from->type.dataType.IsFloatType() )
  4503. {
  4504. float ic = from->type.floatValue;
  4505. double fc = double(ic);
  4506. // Don't check for float->double
  4507. // if( float(fc) != ic )
  4508. // {
  4509. // acCString str;
  4510. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  4511. // if( !isExplicit ) Warning(str, node);
  4512. // }
  4513. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4514. from->type.doubleValue = fc;
  4515. }
  4516. else if( from->type.dataType.IsEnumType() )
  4517. {
  4518. double fc = double(from->type.intValue);
  4519. if( int(fc) != from->type.intValue )
  4520. {
  4521. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4522. }
  4523. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4524. from->type.doubleValue = fc;
  4525. }
  4526. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4527. {
  4528. // Must properly convert value in case the from value is smaller
  4529. int ic;
  4530. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4531. ic = (signed char)from->type.byteValue;
  4532. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4533. ic = (short)from->type.wordValue;
  4534. else
  4535. ic = from->type.intValue;
  4536. double fc = double(ic);
  4537. if( int(fc) != ic )
  4538. {
  4539. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4540. }
  4541. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4542. from->type.doubleValue = fc;
  4543. }
  4544. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4545. {
  4546. double fc = double(asINT64(from->type.qwordValue));
  4547. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4548. {
  4549. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4550. }
  4551. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4552. from->type.doubleValue = fc;
  4553. }
  4554. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4555. {
  4556. // Must properly convert value in case the from value is smaller
  4557. unsigned int uic;
  4558. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4559. uic = from->type.byteValue;
  4560. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4561. uic = from->type.wordValue;
  4562. else
  4563. uic = from->type.dwordValue;
  4564. double fc = double(uic);
  4565. if( (unsigned int)(fc) != uic )
  4566. {
  4567. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4568. }
  4569. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4570. from->type.doubleValue = fc;
  4571. }
  4572. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4573. {
  4574. double fc = double((asINT64)from->type.qwordValue);
  4575. if( asQWORD(fc) != from->type.qwordValue )
  4576. {
  4577. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4578. }
  4579. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4580. from->type.doubleValue = fc;
  4581. }
  4582. }
  4583. }
  4584. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  4585. {
  4586. // Implicit handle types should always be treated as handles in assignments
  4587. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4588. {
  4589. lctx->type.dataType.MakeHandle(true);
  4590. lctx->type.isExplicitHandle = true;
  4591. }
  4592. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  4593. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  4594. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle && !lctx->type.dataType.GetObjectType()->beh.copy)
  4595. lctx->type.isExplicitHandle = true;
  4596. // If the left hand expression is a property accessor, then that should be used
  4597. // to do the assignment instead of the ordinary operator. The exception is when
  4598. // the property accessor is for a handle property, and the operation is a value
  4599. // assignment.
  4600. if( (lctx->property_get || lctx->property_set) &&
  4601. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  4602. {
  4603. if( op != ttAssignment )
  4604. {
  4605. // TODO: getset: We may actually be able to support this, if we can
  4606. // guarantee that the object reference will stay valid
  4607. // between the calls to the get and set accessors.
  4608. // Process the property to free the memory
  4609. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4610. // Compound assignments are not allowed for properties
  4611. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  4612. return -1;
  4613. }
  4614. // It is not allowed to do a handle assignment on a property
  4615. // accessor that doesn't take a handle in the set accessor.
  4616. if( lctx->property_set && lctx->type.isExplicitHandle )
  4617. {
  4618. // set_opIndex has 2 arguments, where as normal setters have only 1
  4619. asCArray<asCDataType>& parameterTypes =
  4620. engine->scriptFunctions[lctx->property_set]->parameterTypes;
  4621. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  4622. {
  4623. // Process the property to free the memory
  4624. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4625. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  4626. return -1;
  4627. }
  4628. }
  4629. MergeExprBytecodeAndType(ctx, lctx);
  4630. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  4631. }
  4632. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4633. {
  4634. // Get the handle to the object that will be used for the value assignment
  4635. ProcessPropertyGetAccessor(lctx, opNode);
  4636. }
  4637. if( lctx->type.dataType.IsPrimitive() )
  4638. {
  4639. if( !lctx->type.isLValue )
  4640. {
  4641. Error(TXT_NOT_LVALUE, lexpr);
  4642. return -1;
  4643. }
  4644. if( op != ttAssignment )
  4645. {
  4646. // Compute the operator before the assignment
  4647. asCTypeInfo lvalue = lctx->type;
  4648. if( lctx->type.isTemporary && !lctx->type.isVariable )
  4649. {
  4650. // The temporary variable must not be freed until the
  4651. // assignment has been performed. lvalue still holds
  4652. // the information about the temporary variable
  4653. lctx->type.isTemporary = false;
  4654. }
  4655. asSExprContext o(engine);
  4656. CompileOperator(opNode, lctx, rctx, &o);
  4657. MergeExprBytecode(rctx, &o);
  4658. rctx->type = o.type;
  4659. // Convert the rvalue to the right type and validate it
  4660. PrepareForAssignment(&lvalue.dataType, rctx, rexpr);
  4661. MergeExprBytecode(ctx, rctx);
  4662. lctx->type = lvalue;
  4663. // The lvalue continues the same, either it was a variable, or a reference in the register
  4664. }
  4665. else
  4666. {
  4667. // Convert the rvalue to the right type and validate it
  4668. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, lctx);
  4669. MergeExprBytecode(ctx, rctx);
  4670. MergeExprBytecode(ctx, lctx);
  4671. }
  4672. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4673. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4674. ctx->type = lctx->type;
  4675. }
  4676. else if( lctx->type.isExplicitHandle )
  4677. {
  4678. if( !lctx->type.isLValue )
  4679. {
  4680. Error(TXT_NOT_LVALUE, lexpr);
  4681. return -1;
  4682. }
  4683. // Object handles don't have any compound assignment operators
  4684. if( op != ttAssignment )
  4685. {
  4686. asCString str;
  4687. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4688. Error(str.AddressOf(), lexpr);
  4689. return -1;
  4690. }
  4691. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  4692. {
  4693. // The object is a value type but that should be treated as a handle
  4694. // TODO: handle: Make sure the right hand value is a handle
  4695. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4696. {
  4697. // An overloaded assignment operator was found (or a compilation error occured)
  4698. return 0;
  4699. }
  4700. // The object must implement the opAssign method
  4701. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  4702. return -1;
  4703. }
  4704. else
  4705. {
  4706. asCDataType dt = lctx->type.dataType;
  4707. dt.MakeReference(false);
  4708. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4709. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4710. {
  4711. asCString str;
  4712. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4713. Error(str.AddressOf(), rexpr);
  4714. return -1;
  4715. }
  4716. MergeExprBytecode(ctx, rctx);
  4717. MergeExprBytecode(ctx, lctx);
  4718. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4719. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4720. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4721. ctx->type = rctx->type;
  4722. }
  4723. }
  4724. else // if( lctx->type.dataType.IsObject() )
  4725. {
  4726. // An ASHANDLE type must not allow a value assignment, as
  4727. // the opAssign operator is used for the handle assignment
  4728. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  4729. {
  4730. asCString str;
  4731. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4732. Error(str.AddressOf(), lexpr);
  4733. return -1;
  4734. }
  4735. // The lvalue reference may be marked as a temporary, if for example
  4736. // it was originated as a handle returned from a function. In such
  4737. // cases it must be possible to assign values to it anyway.
  4738. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4739. {
  4740. // Convert the handle to a object reference
  4741. asCDataType to;
  4742. to = lctx->type.dataType;
  4743. to.MakeHandle(false);
  4744. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  4745. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  4746. }
  4747. // Check for overloaded assignment operator
  4748. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4749. {
  4750. // An overloaded assignment operator was found (or a compilation error occured)
  4751. return 0;
  4752. }
  4753. // No registered operator was found. In case the operation is a direct
  4754. // assignment and the rvalue is the same type as the lvalue, then we can
  4755. // still use the byte-for-byte copy to do the assignment
  4756. if( op != ttAssignment )
  4757. {
  4758. asCString str;
  4759. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4760. Error(str.AddressOf(), lexpr);
  4761. return -1;
  4762. }
  4763. // If the left hand expression is simple, i.e. without any
  4764. // function calls or allocations of memory, then we can avoid
  4765. // doing a copy of the right hand expression (done by PrepareArgument).
  4766. // Instead the reference to the value can be placed directly on the
  4767. // stack.
  4768. //
  4769. // This optimization should only be done for value types, where
  4770. // the application developer is responsible for making the
  4771. // implementation safe against unwanted destruction of the input
  4772. // reference before the time.
  4773. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  4774. // Implicitly convert the rvalue to the type of the lvalue
  4775. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4776. simpleExpr = false;
  4777. if( !simpleExpr )
  4778. {
  4779. asCDataType dt = lctx->type.dataType;
  4780. dt.MakeReference(true);
  4781. dt.MakeReadOnly(true);
  4782. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4783. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4784. {
  4785. asCString str;
  4786. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4787. Error(str.AddressOf(), rexpr);
  4788. return -1;
  4789. }
  4790. }
  4791. else if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  4792. rctx->bc.Instr(asBC_RDSPTR);
  4793. MergeExprBytecode(ctx, rctx);
  4794. MergeExprBytecode(ctx, lctx);
  4795. if( !simpleExpr )
  4796. {
  4797. if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
  4798. // TODO: optimize: Actually the reference can be pushed on the stack directly
  4799. // as the value allocated on the stack is guaranteed to be safe
  4800. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  4801. else
  4802. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4803. }
  4804. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4805. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4806. ctx->type = lctx->type;
  4807. }
  4808. return 0;
  4809. }
  4810. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  4811. {
  4812. asCScriptNode *lexpr = expr->firstChild;
  4813. if( lexpr->next )
  4814. {
  4815. // Compile the two expression terms
  4816. asSExprContext lctx(engine), rctx(engine);
  4817. int rr = CompileAssignment(lexpr->next->next, &rctx);
  4818. int lr = CompileCondition(lexpr, &lctx);
  4819. if( lr >= 0 && rr >= 0 )
  4820. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  4821. // Since the operands failed, the assignment was not computed
  4822. ctx->type.SetDummy();
  4823. return -1;
  4824. }
  4825. return CompileCondition(lexpr, ctx);
  4826. }
  4827. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  4828. {
  4829. asCTypeInfo ctype;
  4830. // Compile the conditional expression
  4831. asCScriptNode *cexpr = expr->firstChild;
  4832. if( cexpr->next )
  4833. {
  4834. //-------------------------------
  4835. // Compile the condition
  4836. asSExprContext e(engine);
  4837. int r = CompileExpression(cexpr, &e);
  4838. if( r < 0 )
  4839. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4840. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  4841. {
  4842. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  4843. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4844. }
  4845. ctype = e.type;
  4846. ProcessPropertyGetAccessor(&e, cexpr);
  4847. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  4848. ProcessDeferredParams(&e);
  4849. //-------------------------------
  4850. // Compile the left expression
  4851. asSExprContext le(engine);
  4852. int lr = CompileAssignment(cexpr->next, &le);
  4853. //-------------------------------
  4854. // Compile the right expression
  4855. asSExprContext re(engine);
  4856. int rr = CompileAssignment(cexpr->next->next, &re);
  4857. if( lr >= 0 && rr >= 0 )
  4858. {
  4859. ProcessPropertyGetAccessor(&le, cexpr->next);
  4860. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  4861. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  4862. // Allow a 0 or null in the first case to be implicitly converted to the second type
  4863. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  4864. {
  4865. asCDataType to = re.type.dataType;
  4866. to.MakeReference(false);
  4867. to.MakeReadOnly(true);
  4868. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  4869. }
  4870. else if( le.type.IsNullConstant() )
  4871. {
  4872. asCDataType to = re.type.dataType;
  4873. to.MakeHandle(true);
  4874. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  4875. }
  4876. //---------------------------------
  4877. // Output the byte code
  4878. int afterLabel = nextLabel++;
  4879. int elseLabel = nextLabel++;
  4880. // If left expression is void, then we don't need to store the result
  4881. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  4882. {
  4883. // Put the code for the condition expression on the output
  4884. MergeExprBytecode(ctx, &e);
  4885. // Added the branch decision
  4886. ctx->type = e.type;
  4887. ConvertToVariable(ctx);
  4888. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4889. ctx->bc.Instr(asBC_ClrHi);
  4890. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4891. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4892. // Add the left expression
  4893. MergeExprBytecode(ctx, &le);
  4894. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4895. // Add the right expression
  4896. ctx->bc.Label((short)elseLabel);
  4897. MergeExprBytecode(ctx, &re);
  4898. ctx->bc.Label((short)afterLabel);
  4899. // Make sure both expressions have the same type
  4900. if( le.type.dataType != re.type.dataType )
  4901. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4902. // Set the type of the result
  4903. ctx->type = le.type;
  4904. }
  4905. else
  4906. {
  4907. // Allocate temporary variable and copy the result to that one
  4908. asCTypeInfo temp;
  4909. temp = le.type;
  4910. temp.dataType.MakeReference(false);
  4911. temp.dataType.MakeReadOnly(false);
  4912. // Make sure the variable isn't used in the initial expression
  4913. asCArray<int> vars;
  4914. e.bc.GetVarsUsed(vars);
  4915. int offset = AllocateVariableNotIn(temp.dataType, true, &vars);
  4916. temp.SetVariable(temp.dataType, offset, true);
  4917. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  4918. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  4919. // Put the code for the condition expression on the output
  4920. MergeExprBytecode(ctx, &e);
  4921. // Add the branch decision
  4922. ctx->type = e.type;
  4923. ConvertToVariable(ctx);
  4924. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4925. ctx->bc.Instr(asBC_ClrHi);
  4926. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4927. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4928. // Assign the result of the left expression to the temporary variable
  4929. asCTypeInfo rtemp;
  4930. rtemp = temp;
  4931. if( rtemp.dataType.IsObjectHandle() )
  4932. rtemp.isExplicitHandle = true;
  4933. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next);
  4934. MergeExprBytecode(ctx, &le);
  4935. if( !rtemp.dataType.IsPrimitive() )
  4936. {
  4937. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4938. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4939. }
  4940. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  4941. if( !rtemp.dataType.IsPrimitive() )
  4942. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4943. // Release the old temporary variable
  4944. ReleaseTemporaryVariable(le.type, &ctx->bc);
  4945. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4946. // Start of the right expression
  4947. ctx->bc.Label((short)elseLabel);
  4948. // Copy the result to the same temporary variable
  4949. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next);
  4950. MergeExprBytecode(ctx, &re);
  4951. if( !rtemp.dataType.IsPrimitive() )
  4952. {
  4953. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4954. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4955. }
  4956. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  4957. if( !rtemp.dataType.IsPrimitive() )
  4958. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4959. // Release the old temporary variable
  4960. ReleaseTemporaryVariable(re.type, &ctx->bc);
  4961. ctx->bc.Label((short)afterLabel);
  4962. // Make sure both expressions have the same type
  4963. if( le.type.dataType != re.type.dataType )
  4964. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4965. // Set the temporary variable as output
  4966. ctx->type = rtemp;
  4967. ctx->type.isExplicitHandle = isExplicitHandle;
  4968. if( !ctx->type.dataType.IsPrimitive() )
  4969. {
  4970. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4971. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4972. }
  4973. // Make sure the output isn't marked as being a literal constant
  4974. ctx->type.isConstant = false;
  4975. }
  4976. }
  4977. else
  4978. {
  4979. ctx->type.SetDummy();
  4980. return -1;
  4981. }
  4982. }
  4983. else
  4984. return CompileExpression(cexpr, ctx);
  4985. return 0;
  4986. }
  4987. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  4988. {
  4989. asASSERT(expr->nodeType == snExpression);
  4990. // Count the nodes
  4991. int count = 0;
  4992. asCScriptNode *node = expr->firstChild;
  4993. while( node )
  4994. {
  4995. count++;
  4996. node = node->next;
  4997. }
  4998. // Convert to polish post fix, i.e: a+b => ab+
  4999. asCArray<asCScriptNode *> stack(count);
  5000. asCArray<asCScriptNode *> stack2(count);
  5001. asCArray<asCScriptNode *> postfix(count);
  5002. node = expr->firstChild;
  5003. while( node )
  5004. {
  5005. int precedence = GetPrecedence(node);
  5006. while( stack.GetLength() > 0 &&
  5007. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  5008. stack2.PushLast(stack.PopLast());
  5009. stack.PushLast(node);
  5010. node = node->next;
  5011. }
  5012. while( stack.GetLength() > 0 )
  5013. stack2.PushLast(stack.PopLast());
  5014. // We need to swap operands so that the left
  5015. // operand is always computed before the right
  5016. SwapPostFixOperands(stack2, postfix);
  5017. // Compile the postfix formatted expression
  5018. return CompilePostFixExpression(&postfix, ctx);
  5019. }
  5020. void asCCompiler::SwapPostFixOperands(asCArray<asCScriptNode *> &postfix, asCArray<asCScriptNode *> &target)
  5021. {
  5022. if( postfix.GetLength() == 0 ) return;
  5023. asCScriptNode *node = postfix.PopLast();
  5024. if( node->nodeType == snExprTerm )
  5025. {
  5026. target.PushLast(node);
  5027. return;
  5028. }
  5029. SwapPostFixOperands(postfix, target);
  5030. SwapPostFixOperands(postfix, target);
  5031. target.PushLast(node);
  5032. }
  5033. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  5034. {
  5035. // Shouldn't send any byte code
  5036. asASSERT(ctx->bc.GetLastInstr() == -1);
  5037. // Set the context to a dummy type to avoid further
  5038. // errors in case the expression fails to compile
  5039. ctx->type.SetDummy();
  5040. // Pop the last node
  5041. asCScriptNode *node = postfix->PopLast();
  5042. ctx->exprNode = node;
  5043. // If term, compile the term
  5044. if( node->nodeType == snExprTerm )
  5045. return CompileExpressionTerm(node, ctx);
  5046. // Compile the two expression terms
  5047. asSExprContext r(engine), l(engine);
  5048. int ret;
  5049. ret = CompilePostFixExpression(postfix, &l); if( ret < 0 ) return ret;
  5050. ret = CompilePostFixExpression(postfix, &r); if( ret < 0 ) return ret;
  5051. // Compile the operation
  5052. return CompileOperator(node, &l, &r, ctx);
  5053. }
  5054. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  5055. {
  5056. // Shouldn't send any byte code
  5057. asASSERT(ctx->bc.GetLastInstr() == -1);
  5058. // Set the type as a dummy by default, in case of any compiler errors
  5059. ctx->type.SetDummy();
  5060. // Compile the value node
  5061. asCScriptNode *vnode = node->firstChild;
  5062. while( vnode->nodeType != snExprValue )
  5063. vnode = vnode->next;
  5064. asSExprContext v(engine);
  5065. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  5066. // Compile post fix operators
  5067. asCScriptNode *pnode = vnode->next;
  5068. while( pnode )
  5069. {
  5070. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  5071. pnode = pnode->next;
  5072. }
  5073. // Compile pre fix operators
  5074. pnode = vnode->prev;
  5075. while( pnode )
  5076. {
  5077. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  5078. pnode = pnode->prev;
  5079. }
  5080. // Return the byte code and final type description
  5081. MergeExprBytecodeAndType(ctx, &v);
  5082. return 0;
  5083. }
  5084. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, asCObjectType *objType)
  5085. {
  5086. bool found = false;
  5087. // It is a local variable or parameter?
  5088. // This is not accessible by default arg expressions
  5089. sVariable *v = 0;
  5090. if( !isCompilingDefaultArg && scope == "" && !objType )
  5091. v = variables->GetVariable(name.AddressOf());
  5092. if( v )
  5093. {
  5094. found = true;
  5095. if( v->isPureConstant )
  5096. ctx->type.SetConstantQW(v->type, v->constantValue);
  5097. else if( v->type.IsPrimitive() )
  5098. {
  5099. if( v->type.IsReference() )
  5100. {
  5101. // Copy the reference into the register
  5102. #if AS_PTR_SIZE == 1
  5103. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)v->stackOffset);
  5104. #else
  5105. ctx->bc.InstrSHORT(asBC_CpyVtoR8, (short)v->stackOffset);
  5106. #endif
  5107. ctx->type.Set(v->type);
  5108. }
  5109. else
  5110. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5111. ctx->type.isLValue = true;
  5112. }
  5113. else
  5114. {
  5115. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  5116. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5117. // If the variable is allocated on the heap we have a reference,
  5118. // otherwise the actual object pointer is pushed on the stack.
  5119. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  5120. // Implicitly dereference handle parameters sent by reference
  5121. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  5122. ctx->bc.Instr(asBC_RDSPTR);
  5123. ctx->type.isLValue = true;
  5124. }
  5125. }
  5126. // Is it a class member?
  5127. // This is not accessible by default arg expressions
  5128. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  5129. {
  5130. if( name == THIS_TOKEN && !objType )
  5131. {
  5132. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  5133. // The object pointer is located at stack position 0
  5134. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5135. ctx->type.SetVariable(dt, 0, false);
  5136. ctx->type.dataType.MakeReference(true);
  5137. ctx->type.isLValue = true;
  5138. found = true;
  5139. }
  5140. if( !found )
  5141. {
  5142. // See if there are any matching property accessors
  5143. asSExprContext access(engine);
  5144. if( objType )
  5145. access.type.Set(asCDataType::CreateObject(objType, false));
  5146. else
  5147. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  5148. access.type.dataType.MakeReference(true);
  5149. int r = 0;
  5150. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5151. {
  5152. // This is an index access, check if there is a property accessor that takes an index arg
  5153. asSExprContext dummyArg(engine);
  5154. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, true);
  5155. }
  5156. if( r == 0 )
  5157. {
  5158. // Normal property access
  5159. r = FindPropertyAccessor(name, &access, errNode, true);
  5160. }
  5161. if( r < 0 ) return -1;
  5162. if( access.property_get || access.property_set )
  5163. {
  5164. if( !objType )
  5165. {
  5166. // Prepare the bytecode for the member access
  5167. // This is only done when accessing through the implicit this pointer
  5168. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5169. }
  5170. MergeExprBytecodeAndType(ctx, &access);
  5171. found = true;
  5172. }
  5173. }
  5174. if( !found )
  5175. {
  5176. asCDataType dt;
  5177. if( objType )
  5178. dt = asCDataType::CreateObject(objType, false);
  5179. else
  5180. dt = asCDataType::CreateObject(outFunc->objectType, false);
  5181. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  5182. if( prop )
  5183. {
  5184. if( !objType )
  5185. {
  5186. // The object pointer is located at stack position 0
  5187. // This is only done when accessing through the implicit this pointer
  5188. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5189. ctx->type.SetVariable(dt, 0, false);
  5190. ctx->type.dataType.MakeReference(true);
  5191. Dereference(ctx, true);
  5192. }
  5193. // TODO: This is the same as what is in CompileExpressionPostOp
  5194. // Put the offset on the stack
  5195. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  5196. if( prop->type.IsReference() )
  5197. ctx->bc.Instr(asBC_RDSPTR);
  5198. // Reference to primitive must be stored in the temp register
  5199. if( prop->type.IsPrimitive() )
  5200. {
  5201. // TODO: optimize: The ADD offset command should store the reference in the register directly
  5202. ctx->bc.Instr(asBC_PopRPtr);
  5203. }
  5204. // Set the new type (keeping info about temp variable)
  5205. ctx->type.dataType = prop->type;
  5206. ctx->type.dataType.MakeReference(true);
  5207. ctx->type.isVariable = false;
  5208. ctx->type.isLValue = true;
  5209. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  5210. {
  5211. // Objects that are members are not references
  5212. ctx->type.dataType.MakeReference(false);
  5213. }
  5214. // If the object reference is const, the property will also be const
  5215. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  5216. found = true;
  5217. }
  5218. }
  5219. }
  5220. // Is it a global property?
  5221. if( !found && (scope == "" || scope == "::") && !objType )
  5222. {
  5223. // See if there are any matching global property accessors
  5224. asSExprContext access(engine);
  5225. int r = 0;
  5226. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5227. {
  5228. // This is an index access, check if there is a property accessor that takes an index arg
  5229. asSExprContext dummyArg(engine);
  5230. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  5231. }
  5232. if( r == 0 )
  5233. {
  5234. // Normal property access
  5235. r = FindPropertyAccessor(name, &access, errNode);
  5236. }
  5237. if( r < 0 ) return -1;
  5238. if( access.property_get || access.property_set )
  5239. {
  5240. // Prepare the bytecode for the function call
  5241. MergeExprBytecodeAndType(ctx, &access);
  5242. found = true;
  5243. }
  5244. // See if there is any matching global property
  5245. if( !found )
  5246. {
  5247. bool isCompiled = true;
  5248. bool isPureConstant = false;
  5249. bool isAppProp = false;
  5250. asQWORD constantValue;
  5251. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  5252. if( prop )
  5253. {
  5254. found = true;
  5255. // Verify that the global property has been compiled already
  5256. if( isCompiled )
  5257. {
  5258. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5259. {
  5260. ctx->type.dataType.MakeHandle(true);
  5261. ctx->type.isExplicitHandle = true;
  5262. }
  5263. // If the global property is a pure constant
  5264. // we can allow the compiler to optimize it. Pure
  5265. // constants are global constant variables that were
  5266. // initialized by literal constants.
  5267. if( isPureConstant )
  5268. ctx->type.SetConstantQW(prop->type, constantValue);
  5269. else
  5270. {
  5271. // A shared type must not access global vars, unless they
  5272. // too are shared, e.g. application registered vars
  5273. if( outFunc->objectType && outFunc->objectType->IsShared() )
  5274. {
  5275. if( !isAppProp )
  5276. {
  5277. asCString str;
  5278. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  5279. Error(str.AddressOf(), errNode);
  5280. // Allow the compilation to continue to catch other problems
  5281. }
  5282. }
  5283. ctx->type.Set(prop->type);
  5284. ctx->type.dataType.MakeReference(true);
  5285. ctx->type.isLValue = true;
  5286. if( ctx->type.dataType.IsPrimitive() )
  5287. {
  5288. // Load the address of the variable into the register
  5289. ctx->bc.InstrPTR(asBC_LDG, engine->globalProperties[prop->id]->GetAddressOfValue());
  5290. }
  5291. else
  5292. {
  5293. // Push the address of the variable on the stack
  5294. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[prop->id]->GetAddressOfValue());
  5295. // If the object is a value type, then we must validate the existance,
  5296. // as it could potentially be accessed before it is initialized.
  5297. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
  5298. !ctx->type.dataType.IsObjectHandle() )
  5299. {
  5300. // TODO: optimize: This is not necessary for application registered properties
  5301. ctx->bc.Instr(asBC_ChkRefS);
  5302. }
  5303. }
  5304. }
  5305. }
  5306. else
  5307. {
  5308. asCString str;
  5309. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  5310. Error(str.AddressOf(), errNode);
  5311. return -1;
  5312. }
  5313. }
  5314. }
  5315. }
  5316. // Is it the name of a global function?
  5317. if( !noFunction && !found && (scope == "" || scope == "::") && !objType )
  5318. {
  5319. asCArray<int> funcs;
  5320. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  5321. if( funcs.GetLength() > 1 )
  5322. {
  5323. // TODO: funcdef: If multiple functions are found, then the compiler should defer the decision
  5324. // to which one it should use until the value is actually used.
  5325. //
  5326. // - assigning the function pointer to a variable
  5327. // - performing an explicit cast
  5328. // - passing the function pointer to a function as parameter
  5329. asCString str;
  5330. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, name.AddressOf());
  5331. Error(str.AddressOf(), errNode);
  5332. return -1;
  5333. }
  5334. else if( funcs.GetLength() == 1 )
  5335. {
  5336. found = true;
  5337. // TODO: shared: A shared object may not access global functions unless they too are shared (e.g. registered functions)
  5338. // Push the function pointer on the stack
  5339. ctx->bc.InstrPTR(asBC_FuncPtr, engine->scriptFunctions[funcs[0]]);
  5340. ctx->type.Set(asCDataType::CreateFuncDef(engine->scriptFunctions[funcs[0]]));
  5341. }
  5342. }
  5343. // Is it an enum value?
  5344. if( !found && !objType )
  5345. {
  5346. asCObjectType *scopeType = 0;
  5347. if( scope != "" )
  5348. {
  5349. // resolve the type before the scope
  5350. scopeType = builder->GetObjectType( scope.AddressOf() );
  5351. }
  5352. asDWORD value = 0;
  5353. asCDataType dt;
  5354. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  5355. {
  5356. // scoped enum value found
  5357. found = true;
  5358. }
  5359. else if( scope == "" && !engine->ep.requireEnumScope )
  5360. {
  5361. // look for the enum value with no namespace
  5362. int e = builder->GetEnumValue(name.AddressOf(), dt, value);
  5363. if( e )
  5364. {
  5365. found = true;
  5366. if( e == 2 )
  5367. {
  5368. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  5369. }
  5370. }
  5371. }
  5372. if( found )
  5373. {
  5374. // Even if the enum type is not shared, and we're compiling a shared object,
  5375. // the use of the values are still allowed, since they are treated as constants.
  5376. // an enum value was resolved
  5377. ctx->type.SetConstantDW(dt, value);
  5378. }
  5379. }
  5380. // The name doesn't match any variable
  5381. if( !found )
  5382. {
  5383. // Give dummy value
  5384. ctx->type.SetDummy();
  5385. if( !isOptional )
  5386. {
  5387. // Prepend the scope to the name for the error message
  5388. asCString ename;
  5389. if( scope != "" && scope != "::" )
  5390. ename = scope + "::";
  5391. else
  5392. ename = scope;
  5393. ename += name;
  5394. asCString str;
  5395. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  5396. Error(str.AddressOf(), errNode);
  5397. // Declare the variable now so that it will not be reported again
  5398. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  5399. // Mark the variable as initialized so that the user will not be bother by it again
  5400. sVariable *v = variables->GetVariable(name.AddressOf());
  5401. asASSERT(v);
  5402. if( v ) v->isInitialized = true;
  5403. }
  5404. // Return -1 to signal that the variable wasn't found
  5405. return -1;
  5406. }
  5407. return 0;
  5408. }
  5409. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  5410. {
  5411. // Shouldn't receive any byte code
  5412. asASSERT(ctx->bc.GetLastInstr() == -1);
  5413. asCScriptNode *vnode = node->firstChild;
  5414. ctx->exprNode = vnode;
  5415. if( vnode->nodeType == snVariableAccess )
  5416. {
  5417. // Determine the scope resolution of the variable
  5418. asCString scope = GetScopeFromNode(vnode);
  5419. // Determine the name of the variable
  5420. vnode = vnode->lastChild;
  5421. asASSERT(vnode->nodeType == snIdentifier );
  5422. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  5423. return CompileVariableAccess(name, scope, ctx, node);
  5424. }
  5425. else if( vnode->nodeType == snConstant )
  5426. {
  5427. if( vnode->tokenType == ttIntConstant )
  5428. {
  5429. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5430. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  5431. // Do we need 64 bits?
  5432. if( val>>32 )
  5433. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5434. else
  5435. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5436. }
  5437. else if( vnode->tokenType == ttBitsConstant )
  5438. {
  5439. asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
  5440. // TODO: Check for overflow
  5441. asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
  5442. // Do we need 64 bits?
  5443. if( val>>32 )
  5444. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5445. else
  5446. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5447. }
  5448. else if( vnode->tokenType == ttFloatConstant )
  5449. {
  5450. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5451. // TODO: Check for overflow
  5452. size_t numScanned;
  5453. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  5454. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  5455. #ifndef AS_USE_DOUBLE_AS_FLOAT
  5456. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  5457. asASSERT(numScanned == vnode->tokenLength - 1);
  5458. #endif
  5459. }
  5460. else if( vnode->tokenType == ttDoubleConstant )
  5461. {
  5462. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5463. // TODO: Check for overflow
  5464. size_t numScanned;
  5465. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  5466. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  5467. asASSERT(numScanned == vnode->tokenLength);
  5468. }
  5469. else if( vnode->tokenType == ttTrue ||
  5470. vnode->tokenType == ttFalse )
  5471. {
  5472. #if AS_SIZEOF_BOOL == 1
  5473. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5474. #else
  5475. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5476. #endif
  5477. }
  5478. else if( vnode->tokenType == ttStringConstant ||
  5479. vnode->tokenType == ttMultilineStringConstant ||
  5480. vnode->tokenType == ttHeredocStringConstant )
  5481. {
  5482. asCString str;
  5483. asCScriptNode *snode = vnode->firstChild;
  5484. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  5485. {
  5486. // Treat the single quoted string as a single character literal
  5487. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5488. asDWORD val = 0;
  5489. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  5490. {
  5491. // This is the start of a UTF8 encoded character. We need to decode it
  5492. val = asStringDecodeUTF8(str.AddressOf(), 0);
  5493. if( val == (asDWORD)-1 )
  5494. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5495. }
  5496. else
  5497. {
  5498. val = ProcessStringConstant(str, snode);
  5499. if( val == (asDWORD)-1 )
  5500. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5501. }
  5502. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  5503. }
  5504. else
  5505. {
  5506. // Process the string constants
  5507. while( snode )
  5508. {
  5509. asCString cat;
  5510. if( snode->tokenType == ttStringConstant )
  5511. {
  5512. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5513. ProcessStringConstant(cat, snode);
  5514. }
  5515. else if( snode->tokenType == ttMultilineStringConstant )
  5516. {
  5517. if( !engine->ep.allowMultilineStrings )
  5518. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  5519. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5520. ProcessStringConstant(cat, snode);
  5521. }
  5522. else if( snode->tokenType == ttHeredocStringConstant )
  5523. {
  5524. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  5525. ProcessHeredocStringConstant(cat, snode);
  5526. }
  5527. str += cat;
  5528. snode = snode->next;
  5529. }
  5530. // Call the string factory function to create a string object
  5531. asCScriptFunction *descr = engine->stringFactory;
  5532. if( descr == 0 )
  5533. {
  5534. // Error
  5535. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  5536. // Give dummy value
  5537. ctx->type.SetDummy();
  5538. return -1;
  5539. }
  5540. else
  5541. {
  5542. // Register the constant string with the engine
  5543. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  5544. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  5545. bool useVariable = false;
  5546. int stackOffset = 0;
  5547. #ifndef AS_OLD
  5548. if( descr->DoesReturnOnStack() )
  5549. {
  5550. useVariable = true;
  5551. stackOffset = AllocateVariable(descr->returnType, true);
  5552. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5553. }
  5554. #endif
  5555. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  5556. }
  5557. }
  5558. }
  5559. else if( vnode->tokenType == ttNull )
  5560. {
  5561. #ifndef AS_64BIT_PTR
  5562. ctx->bc.InstrDWORD(asBC_PshC4, 0);
  5563. #else
  5564. ctx->bc.InstrQWORD(asBC_PshC8, 0);
  5565. #endif
  5566. ctx->type.SetNullConstant();
  5567. }
  5568. else
  5569. asASSERT(false);
  5570. }
  5571. else if( vnode->nodeType == snFunctionCall )
  5572. {
  5573. bool found = false;
  5574. // Determine the scope resolution
  5575. asCString scope = GetScopeFromNode(vnode);
  5576. if( outFunc && outFunc->objectType && scope != "::" )
  5577. {
  5578. // TODO: funcdef: There may be a local variable of a function type with the same name
  5579. // Check if a class method is being called
  5580. asCScriptNode *nm = vnode->lastChild->prev;
  5581. asCString name;
  5582. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  5583. asCArray<int> funcs;
  5584. // If we're compiling a constructor and the name of the function called
  5585. // is 'super' then the base class' constructor is being called.
  5586. // super cannot be called from another scope, i.e. must not be prefixed
  5587. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  5588. {
  5589. // Actually it is the base class' constructor that is being called,
  5590. // but as we won't use the actual function ids here we can take the
  5591. // object's own constructors and avoid the need to check if the
  5592. // object actually derives from any other class
  5593. funcs = outFunc->objectType->beh.constructors;
  5594. // Must not allow calling constructors multiple times
  5595. if( continueLabels.GetLength() > 0 )
  5596. {
  5597. // If a continue label is set we are in a loop
  5598. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, vnode);
  5599. }
  5600. else if( breakLabels.GetLength() > 0 )
  5601. {
  5602. // TODO: inheritance: Should eventually allow constructors in switch statements
  5603. // If a break label is set we are either in a loop or a switch statements
  5604. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, vnode);
  5605. }
  5606. else if( m_isConstructorCalled )
  5607. {
  5608. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, vnode);
  5609. }
  5610. m_isConstructorCalled = true;
  5611. }
  5612. else
  5613. builder->GetObjectMethodDescriptions(name.AddressOf(), outFunc->objectType, funcs, false);
  5614. if( funcs.GetLength() )
  5615. {
  5616. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, false);
  5617. // The object pointer is located at stack position 0
  5618. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5619. ctx->type.SetVariable(dt, 0, false);
  5620. ctx->type.dataType.MakeReference(true);
  5621. // TODO: optimize: This adds a CHKREF. Is that really necessary?
  5622. Dereference(ctx, true);
  5623. CompileFunctionCall(vnode, ctx, outFunc->objectType, false, scope);
  5624. found = true;
  5625. }
  5626. }
  5627. if( !found )
  5628. CompileFunctionCall(vnode, ctx, 0, false, scope);
  5629. }
  5630. else if( vnode->nodeType == snConstructCall )
  5631. {
  5632. CompileConstructCall(vnode, ctx);
  5633. }
  5634. else if( vnode->nodeType == snAssignment )
  5635. {
  5636. asSExprContext e(engine);
  5637. int r = CompileAssignment(vnode, &e);
  5638. if( r < 0 )
  5639. {
  5640. ctx->type.SetDummy();
  5641. return r;
  5642. }
  5643. MergeExprBytecodeAndType(ctx, &e);
  5644. }
  5645. else if( vnode->nodeType == snCast )
  5646. {
  5647. // Implement the cast operator
  5648. CompileConversion(vnode, ctx);
  5649. }
  5650. else
  5651. asASSERT(false);
  5652. return 0;
  5653. }
  5654. asCString asCCompiler::GetScopeFromNode(asCScriptNode *node)
  5655. {
  5656. asCString scope;
  5657. asCScriptNode *sn = node->firstChild;
  5658. if( sn->tokenType == ttScope )
  5659. {
  5660. // Global scope
  5661. scope = "::";
  5662. sn = sn->next;
  5663. }
  5664. else if( sn->next && sn->next->tokenType == ttScope )
  5665. {
  5666. scope.Assign(&script->code[sn->tokenPos], sn->tokenLength);
  5667. sn = sn->next->next;
  5668. }
  5669. if( scope != "" )
  5670. {
  5671. // We don't support multiple levels of scope yet
  5672. if( sn->next && sn->next->tokenType == ttScope )
  5673. {
  5674. Error(TXT_INVALID_SCOPE, sn->next);
  5675. }
  5676. }
  5677. return scope;
  5678. }
  5679. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  5680. {
  5681. int charLiteral = -1;
  5682. // Process escape sequences
  5683. asCArray<char> str((int)cstr.GetLength());
  5684. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  5685. {
  5686. #ifdef AS_DOUBLEBYTE_CHARSET
  5687. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  5688. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  5689. {
  5690. // This is the lead character of a double byte character
  5691. // include the trail character without checking it's value.
  5692. str.PushLast(cstr[n]);
  5693. n++;
  5694. str.PushLast(cstr[n]);
  5695. continue;
  5696. }
  5697. #endif
  5698. asUINT val;
  5699. if( processEscapeSequences && cstr[n] == '\\' )
  5700. {
  5701. ++n;
  5702. if( n == cstr.GetLength() )
  5703. {
  5704. if( charLiteral == -1 ) charLiteral = 0;
  5705. return charLiteral;
  5706. }
  5707. // TODO: Consider deprecating use of hexadecimal escape sequences,
  5708. // as they do not guarantee proper unicode sequences
  5709. if( cstr[n] == 'x' || cstr[n] == 'X' )
  5710. {
  5711. ++n;
  5712. if( n == cstr.GetLength() ) break;
  5713. val = 0;
  5714. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  5715. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  5716. {
  5717. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5718. val = val*16 + cstr[n] - '0';
  5719. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5720. val = val*16 + cstr[n] - 'a' + 10;
  5721. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5722. val = val*16 + cstr[n] - 'A' + 10;
  5723. else
  5724. break;
  5725. }
  5726. // Rewind one, since the loop will increment it again
  5727. n--;
  5728. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  5729. if( engine->ep.stringEncoding == 0 )
  5730. {
  5731. str.PushLast((asBYTE)val);
  5732. }
  5733. else
  5734. {
  5735. #ifndef AS_BIG_ENDIAN
  5736. str.PushLast((asBYTE)val);
  5737. str.PushLast((asBYTE)(val>>8));
  5738. #else
  5739. str.PushLast((asBYTE)(val>>8));
  5740. str.PushLast((asBYTE)val);
  5741. #endif
  5742. }
  5743. if( charLiteral == -1 ) charLiteral = val;
  5744. continue;
  5745. }
  5746. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  5747. {
  5748. // \u expects 4 hex digits
  5749. // \U expects 8 hex digits
  5750. bool expect2 = cstr[n] == 'u';
  5751. int c = expect2 ? 4 : 8;
  5752. val = 0;
  5753. for( ; c > 0; c-- )
  5754. {
  5755. ++n;
  5756. if( n == cstr.GetLength() ) break;
  5757. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5758. val = val*16 + cstr[n] - '0';
  5759. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5760. val = val*16 + cstr[n] - 'a' + 10;
  5761. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5762. val = val*16 + cstr[n] - 'A' + 10;
  5763. else
  5764. break;
  5765. }
  5766. if( c != 0 )
  5767. {
  5768. // Give warning about invalid code point
  5769. // TODO: Need code position for warning
  5770. asCString msg;
  5771. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  5772. Warning(msg.AddressOf(), node);
  5773. continue;
  5774. }
  5775. }
  5776. else
  5777. {
  5778. if( cstr[n] == '"' )
  5779. val = '"';
  5780. else if( cstr[n] == '\'' )
  5781. val = '\'';
  5782. else if( cstr[n] == 'n' )
  5783. val = '\n';
  5784. else if( cstr[n] == 'r' )
  5785. val = '\r';
  5786. else if( cstr[n] == 't' )
  5787. val = '\t';
  5788. else if( cstr[n] == '0' )
  5789. val = '\0';
  5790. else if( cstr[n] == '\\' )
  5791. val = '\\';
  5792. else
  5793. {
  5794. // Invalid escape sequence
  5795. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  5796. continue;
  5797. }
  5798. }
  5799. }
  5800. else
  5801. {
  5802. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  5803. {
  5804. unsigned int len;
  5805. val = asStringDecodeUTF8(&cstr[n], &len);
  5806. if( val == 0xFFFFFFFF )
  5807. {
  5808. // Incorrect UTF8 encoding. Use only the first byte
  5809. // TODO: Need code position for warning
  5810. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  5811. val = (unsigned char)cstr[n];
  5812. }
  5813. else
  5814. n += len-1;
  5815. }
  5816. else
  5817. val = (unsigned char)cstr[n];
  5818. }
  5819. // Add the character to the final string
  5820. char encodedValue[5];
  5821. int len;
  5822. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  5823. {
  5824. // Convert to UTF8 encoded
  5825. len = asStringEncodeUTF8(val, encodedValue);
  5826. }
  5827. else if( engine->ep.stringEncoding == 1 )
  5828. {
  5829. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  5830. len = asStringEncodeUTF16(val, encodedValue);
  5831. }
  5832. else
  5833. {
  5834. // Do not convert ASCII characters
  5835. encodedValue[0] = (asBYTE)val;
  5836. len = 1;
  5837. }
  5838. if( len < 0 )
  5839. {
  5840. // Give warning about invalid code point
  5841. // TODO: Need code position for warning
  5842. Warning(TXT_INVALID_UNICODE_VALUE, node);
  5843. }
  5844. else
  5845. {
  5846. // Add the encoded value to the final string
  5847. str.Concatenate(encodedValue, len);
  5848. if( charLiteral == -1 ) charLiteral = val;
  5849. }
  5850. }
  5851. cstr.Assign(str.AddressOf(), str.GetLength());
  5852. return charLiteral;
  5853. }
  5854. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  5855. {
  5856. // Remove first line if it only contains whitespace
  5857. int start;
  5858. for( start = 0; start < (int)str.GetLength(); start++ )
  5859. {
  5860. if( str[start] == '\n' )
  5861. {
  5862. // Remove the linebreak as well
  5863. start++;
  5864. break;
  5865. }
  5866. if( str[start] != ' ' &&
  5867. str[start] != '\t' &&
  5868. str[start] != '\r' )
  5869. {
  5870. // Don't remove anything
  5871. start = 0;
  5872. break;
  5873. }
  5874. }
  5875. // Remove last line break and the line after that if it only contains whitespaces
  5876. int end;
  5877. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  5878. {
  5879. if( str[end] == '\n' )
  5880. break;
  5881. if( str[end] != ' ' &&
  5882. str[end] != '\t' &&
  5883. str[end] != '\r' )
  5884. {
  5885. // Don't remove anything
  5886. end = (int)str.GetLength();
  5887. break;
  5888. }
  5889. }
  5890. if( end < 0 ) end = 0;
  5891. asCString tmp;
  5892. if( end > start )
  5893. tmp.Assign(&str[start], end-start);
  5894. ProcessStringConstant(tmp, node, false);
  5895. str = tmp;
  5896. }
  5897. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  5898. {
  5899. asSExprContext expr(engine);
  5900. asCDataType to;
  5901. bool anyErrors = false;
  5902. EImplicitConv convType;
  5903. if( node->nodeType == snConstructCall )
  5904. {
  5905. convType = asIC_EXPLICIT_VAL_CAST;
  5906. // Verify that there is only one argument
  5907. if( node->lastChild->firstChild == 0 ||
  5908. node->lastChild->firstChild != node->lastChild->lastChild )
  5909. {
  5910. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  5911. expr.type.SetDummy();
  5912. anyErrors = true;
  5913. }
  5914. else
  5915. {
  5916. // Compile the expression
  5917. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  5918. if( r < 0 )
  5919. anyErrors = true;
  5920. }
  5921. // Determine the requested type
  5922. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5923. to.MakeReadOnly(true); // Default to const
  5924. asASSERT(to.IsPrimitive());
  5925. }
  5926. else
  5927. {
  5928. convType = asIC_EXPLICIT_REF_CAST;
  5929. // Compile the expression
  5930. int r = CompileAssignment(node->lastChild, &expr);
  5931. if( r < 0 )
  5932. anyErrors = true;
  5933. // Determine the requested type
  5934. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5935. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  5936. // If the type support object handles, then use it
  5937. if( to.SupportHandles() )
  5938. {
  5939. to.MakeHandle(true);
  5940. }
  5941. else if( !to.IsObjectHandle() )
  5942. {
  5943. // The cast<type> operator can only be used for reference casts
  5944. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  5945. anyErrors = true;
  5946. }
  5947. }
  5948. if( anyErrors )
  5949. {
  5950. // Assume that the error can be fixed and allow the compilation to continue
  5951. ctx->type.SetConstantDW(to, 0);
  5952. return;
  5953. }
  5954. ProcessPropertyGetAccessor(&expr, node);
  5955. // We don't want a reference
  5956. if( expr.type.dataType.IsReference() )
  5957. {
  5958. if( expr.type.dataType.IsObject() )
  5959. {
  5960. // ASHANDLE is actually a value type, even though it looks like a handle
  5961. // For this reason we shouldn't dereference it, unless it is on the heap
  5962. if( !(expr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) ||
  5963. (expr.type.isVariable && IsVariableOnHeap(expr.type.stackOffset)) )
  5964. Dereference(&expr, true);
  5965. }
  5966. else
  5967. ConvertToVariable(&expr);
  5968. }
  5969. ImplicitConversion(&expr, to, node, convType);
  5970. IsVariableInitialized(&expr.type, node);
  5971. // If no type conversion is really tried ignore it
  5972. if( to == expr.type.dataType )
  5973. {
  5974. // This will keep information about constant type
  5975. MergeExprBytecode(ctx, &expr);
  5976. ctx->type = expr.type;
  5977. return;
  5978. }
  5979. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  5980. {
  5981. MergeExprBytecode(ctx, &expr);
  5982. ctx->type = expr.type;
  5983. ctx->type.dataType.MakeReadOnly(true);
  5984. return;
  5985. }
  5986. // The implicit conversion already does most of the conversions permitted,
  5987. // here we'll only treat those conversions that require an explicit cast.
  5988. bool conversionOK = false;
  5989. if( !expr.type.isConstant )
  5990. {
  5991. if( !expr.type.dataType.IsObject() )
  5992. ConvertToTempVariable(&expr);
  5993. if( to.IsObjectHandle() &&
  5994. expr.type.dataType.IsObjectHandle() &&
  5995. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  5996. {
  5997. conversionOK = CompileRefCast(&expr, to, true, node);
  5998. MergeExprBytecode(ctx, &expr);
  5999. ctx->type = expr.type;
  6000. }
  6001. }
  6002. if( conversionOK )
  6003. return;
  6004. // Conversion not available
  6005. ctx->type.SetDummy();
  6006. asCString strTo, strFrom;
  6007. strTo = to.Format();
  6008. strFrom = expr.type.dataType.Format();
  6009. asCString msg;
  6010. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  6011. Error(msg.AddressOf(), node);
  6012. }
  6013. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  6014. {
  6015. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  6016. // Parameters that are sent by reference should be assigned
  6017. // to the evaluated expression if it is an lvalue
  6018. // Evaluate the arguments from last to first
  6019. int n = (int)descr->parameterTypes.GetLength() - 1;
  6020. for( ; n >= 0; n-- )
  6021. {
  6022. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  6023. (descr->parameterTypes[n].IsObject() && deferAll) )
  6024. {
  6025. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  6026. // For &inout, only store the argument if it is for a temporary variable
  6027. if( engine->ep.allowUnsafeReferences ||
  6028. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  6029. {
  6030. // Store the argument for later processing
  6031. asSDeferredParam outParam;
  6032. outParam.argNode = args[n]->exprNode;
  6033. outParam.argType = args[n]->type;
  6034. outParam.argInOutFlags = descr->inOutFlags[n];
  6035. outParam.origExpr = args[n]->origExpr;
  6036. ctx->deferredParams.PushLast(outParam);
  6037. }
  6038. }
  6039. else
  6040. {
  6041. // Release the temporary variable now
  6042. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  6043. }
  6044. // Move the argument's deferred expressions over to the final expression
  6045. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  6046. {
  6047. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  6048. args[n]->deferredParams[m].origExpr = 0;
  6049. }
  6050. args[n]->deferredParams.SetLength(0);
  6051. }
  6052. }
  6053. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  6054. {
  6055. if( isProcessingDeferredParams ) return;
  6056. isProcessingDeferredParams = true;
  6057. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  6058. {
  6059. asSDeferredParam outParam = ctx->deferredParams[n];
  6060. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  6061. {
  6062. // Just release the variable
  6063. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6064. }
  6065. else if( outParam.argInOutFlags == asTM_OUTREF )
  6066. {
  6067. asSExprContext *expr = outParam.origExpr;
  6068. outParam.origExpr = 0;
  6069. if( outParam.argType.dataType.IsObjectHandle() )
  6070. {
  6071. // Implicitly convert the value to a handle
  6072. if( expr->type.dataType.IsObjectHandle() )
  6073. expr->type.isExplicitHandle = true;
  6074. }
  6075. // Verify that the expression result in a lvalue, or a property accessor
  6076. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  6077. {
  6078. asSExprContext rctx(engine);
  6079. rctx.type = outParam.argType;
  6080. if( rctx.type.dataType.IsPrimitive() )
  6081. rctx.type.dataType.MakeReference(false);
  6082. else
  6083. {
  6084. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  6085. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  6086. if( expr->type.isExplicitHandle )
  6087. rctx.type.isExplicitHandle = true;
  6088. }
  6089. asSExprContext o(engine);
  6090. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  6091. if( !o.type.dataType.IsPrimitive() ) o.bc.Pop(AS_PTR_SIZE);
  6092. MergeExprBytecode(ctx, &o);
  6093. }
  6094. else
  6095. {
  6096. // We must still evaluate the expression
  6097. MergeExprBytecode(ctx, expr);
  6098. if( !expr->type.isConstant || expr->type.IsNullConstant() )
  6099. ctx->bc.Pop(expr->type.dataType.GetSizeOnStackDWords());
  6100. // Give a warning, except if the argument is null which indicate the argument is really to be ignored
  6101. if( !expr->type.IsNullConstant() )
  6102. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  6103. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6104. }
  6105. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  6106. // Delete the original expression context
  6107. asDELETE(expr,asSExprContext);
  6108. }
  6109. else // &inout
  6110. {
  6111. if( outParam.argType.isTemporary )
  6112. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6113. else if( !outParam.argType.isVariable )
  6114. {
  6115. if( outParam.argType.dataType.IsObject() &&
  6116. outParam.argType.dataType.GetBehaviour()->addref &&
  6117. outParam.argType.dataType.GetBehaviour()->release )
  6118. {
  6119. // Release the object handle that was taken to guarantee the reference
  6120. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6121. }
  6122. }
  6123. }
  6124. }
  6125. ctx->deferredParams.SetLength(0);
  6126. isProcessingDeferredParams = false;
  6127. }
  6128. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  6129. {
  6130. // TODO: shared: Do not allow constructing non-shared types
  6131. // The first node is a datatype node
  6132. asCString name;
  6133. asCTypeInfo tempObj;
  6134. bool onHeap = true;
  6135. asCArray<int> funcs;
  6136. // It is possible that the name is really a constructor
  6137. asCDataType dt;
  6138. dt = builder->CreateDataTypeFromNode(node->firstChild, script);
  6139. if( dt.IsPrimitive() )
  6140. {
  6141. // This is a cast to a primitive type
  6142. CompileConversion(node, ctx);
  6143. return;
  6144. }
  6145. // Compile the arguments
  6146. asCArray<asSExprContext *> args;
  6147. asCArray<asCTypeInfo> temporaryVariables;
  6148. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6149. {
  6150. // Check for a value cast behaviour
  6151. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  6152. {
  6153. asSExprContext conv(engine);
  6154. conv.type = args[0]->type;
  6155. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  6156. if( conv.type.dataType.IsEqualExceptRef(dt) )
  6157. {
  6158. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  6159. ctx->bc.AddCode(&args[0]->bc);
  6160. ctx->type = args[0]->type;
  6161. asDELETE(args[0],asSExprContext);
  6162. return;
  6163. }
  6164. }
  6165. // Check for possible constructor/factory
  6166. name = dt.Format();
  6167. asSTypeBehaviour *beh = dt.GetBehaviour();
  6168. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6169. {
  6170. funcs = beh->constructors;
  6171. // Value types and script types are allocated through the constructor
  6172. tempObj.dataType = dt;
  6173. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  6174. tempObj.dataType.MakeReference(true);
  6175. tempObj.isTemporary = true;
  6176. tempObj.isVariable = true;
  6177. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6178. // Push the address of the object on the stack
  6179. if( onHeap )
  6180. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6181. }
  6182. else
  6183. {
  6184. funcs = beh->factories;
  6185. }
  6186. // Special case: Allow calling func(void) with a void expression.
  6187. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6188. {
  6189. // Evaluate the expression before the function call
  6190. MergeExprBytecode(ctx, args[0]);
  6191. asDELETE(args[0],asSExprContext);
  6192. args.SetLength(0);
  6193. }
  6194. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  6195. // If none has been registered, just allocate the variable and push it on the stack.
  6196. if( args.GetLength() == 0 )
  6197. {
  6198. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  6199. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  6200. {
  6201. // Call the default constructor
  6202. ctx->type = tempObj;
  6203. if( onHeap )
  6204. {
  6205. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  6206. ctx->bc.RemoveLastInstr();
  6207. }
  6208. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  6209. // Push the reference on the stack
  6210. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6211. return;
  6212. }
  6213. }
  6214. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  6215. if( funcs.GetLength() != 1 )
  6216. {
  6217. // The error was reported by MatchFunctions()
  6218. // Dummy value
  6219. ctx->type.SetDummy();
  6220. }
  6221. else
  6222. {
  6223. int r = asSUCCESS;
  6224. // Add the default values for arguments not explicitly supplied
  6225. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6226. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6227. r = CompileDefaultArgs(node, args, func);
  6228. if( r == asSUCCESS )
  6229. {
  6230. asCByteCode objBC(engine);
  6231. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6232. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6233. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6234. {
  6235. // If the object is allocated on the stack, then call the constructor as a normal function
  6236. if( onHeap )
  6237. {
  6238. int offset = 0;
  6239. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6240. for( asUINT n = 0; n < args.GetLength(); n++ )
  6241. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6242. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6243. }
  6244. else
  6245. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6246. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  6247. // The constructor doesn't return anything,
  6248. // so we have to manually inform the type of
  6249. // the return value
  6250. ctx->type = tempObj;
  6251. if( !onHeap )
  6252. ctx->type.dataType.MakeReference(false);
  6253. // Push the address of the object on the stack again
  6254. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6255. }
  6256. else
  6257. {
  6258. // Call the factory to create the reference type
  6259. PerformFunctionCall(funcs[0], ctx, false, &args);
  6260. }
  6261. }
  6262. }
  6263. }
  6264. else
  6265. {
  6266. // Failed to compile the argument list, set the result to the dummy type
  6267. ctx->type.SetDummy();
  6268. }
  6269. // Cleanup
  6270. for( asUINT n = 0; n < args.GetLength(); n++ )
  6271. if( args[n] )
  6272. {
  6273. asDELETE(args[n],asSExprContext);
  6274. }
  6275. }
  6276. void asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  6277. {
  6278. asCString name;
  6279. asCTypeInfo tempObj;
  6280. asCArray<int> funcs;
  6281. int r = -1;
  6282. asCScriptNode *nm = node->lastChild->prev;
  6283. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  6284. // First check for a local variable of a function type
  6285. // Must not allow function names, nor global variables to be returned in this instance
  6286. asSExprContext funcPtr(engine);
  6287. if( objectType == 0 )
  6288. r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  6289. if( r < 0 )
  6290. {
  6291. if( objectType )
  6292. {
  6293. // If we're compiling a constructor and the name of the function is super then
  6294. // the constructor of the base class is being called.
  6295. // super cannot be prefixed with a scope operator
  6296. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  6297. {
  6298. // If the class is not derived from anyone else, calling super should give an error
  6299. if( objectType->derivedFrom )
  6300. funcs = objectType->derivedFrom->beh.constructors;
  6301. }
  6302. else
  6303. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType, funcs, objIsConst, scope);
  6304. // It is still possible that there is a class member of a function type
  6305. if( funcs.GetLength() == 0 )
  6306. CompileVariableAccess(name, scope, &funcPtr, node, true, true, objectType);
  6307. }
  6308. else
  6309. {
  6310. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  6311. // TODO: funcdef: It is still possible that there is a global variable of a function type
  6312. }
  6313. }
  6314. else if( !funcPtr.type.dataType.GetFuncDef() )
  6315. {
  6316. // The variable is not a function
  6317. asCString msg;
  6318. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  6319. Error(msg.AddressOf(), node);
  6320. return;
  6321. }
  6322. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  6323. {
  6324. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  6325. }
  6326. // Compile the arguments
  6327. asCArray<asSExprContext *> args;
  6328. asCArray<asCTypeInfo> temporaryVariables;
  6329. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6330. {
  6331. // Special case: Allow calling func(void) with a void expression.
  6332. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6333. {
  6334. // Evaluate the expression before the function call
  6335. MergeExprBytecode(ctx, args[0]);
  6336. asDELETE(args[0],asSExprContext);
  6337. args.SetLength(0);
  6338. }
  6339. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  6340. if( funcs.GetLength() != 1 )
  6341. {
  6342. // The error was reported by MatchFunctions()
  6343. // Dummy value
  6344. ctx->type.SetDummy();
  6345. }
  6346. else
  6347. {
  6348. int r = asSUCCESS;
  6349. // Add the default values for arguments not explicitly supplied
  6350. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6351. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6352. r = CompileDefaultArgs(node, args, func);
  6353. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  6354. // is it enough to make sure it is in a local variable?
  6355. // For function pointer we must guarantee that the function is safe, i.e.
  6356. // by first storing the function pointer in a local variable (if it isn't already in one)
  6357. if( r == asSUCCESS )
  6358. {
  6359. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6360. {
  6361. if( objectType )
  6362. {
  6363. Dereference(ctx, true); // Dereference the object pointer to access the member
  6364. // The actual function should be called as if a global function
  6365. objectType = 0;
  6366. }
  6367. Dereference(&funcPtr, true);
  6368. ConvertToVariable(&funcPtr);
  6369. ctx->bc.AddCode(&funcPtr.bc);
  6370. if( !funcPtr.type.isTemporary )
  6371. ctx->bc.Pop(AS_PTR_SIZE);
  6372. }
  6373. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  6374. // If the function pointer was copied to a local variable for the call, then
  6375. // release it again (temporary local variable)
  6376. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6377. {
  6378. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  6379. }
  6380. }
  6381. }
  6382. }
  6383. else
  6384. {
  6385. // Failed to compile the argument list, set the dummy type and continue compilation
  6386. ctx->type.SetDummy();
  6387. }
  6388. // Cleanup
  6389. for( asUINT n = 0; n < args.GetLength(); n++ )
  6390. if( args[n] )
  6391. {
  6392. asDELETE(args[n],asSExprContext);
  6393. }
  6394. }
  6395. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  6396. {
  6397. int op = node->tokenType;
  6398. IsVariableInitialized(&ctx->type, node);
  6399. if( op == ttHandle )
  6400. {
  6401. // Verify that the type allow its handle to be taken
  6402. if( ctx->type.isExplicitHandle ||
  6403. !ctx->type.dataType.IsObject() ||
  6404. !((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  6405. {
  6406. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  6407. return -1;
  6408. }
  6409. // Objects that are not local variables are not references
  6410. if( !ctx->type.dataType.IsReference() && !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) )
  6411. {
  6412. Error(TXT_NOT_VALID_REFERENCE, node);
  6413. return -1;
  6414. }
  6415. // If this is really an object then the handle created is a const handle
  6416. bool makeConst = !ctx->type.dataType.IsObjectHandle();
  6417. // Mark the type as an object handle
  6418. ctx->type.dataType.MakeHandle(true);
  6419. ctx->type.isExplicitHandle = true;
  6420. if( makeConst )
  6421. ctx->type.dataType.MakeReadOnly(true);
  6422. }
  6423. else if( (op == ttMinus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6424. {
  6425. // Look for the appropriate method
  6426. const char *opName = 0;
  6427. switch( op )
  6428. {
  6429. case ttMinus: opName = "opNeg"; break;
  6430. case ttBitNot: opName = "opCom"; break;
  6431. case ttInc: opName = "opPreInc"; break;
  6432. case ttDec: opName = "opPreDec"; break;
  6433. }
  6434. if( opName )
  6435. {
  6436. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6437. ProcessPropertyGetAccessor(ctx, node);
  6438. // Is it a const value?
  6439. bool isConst = false;
  6440. if( ctx->type.dataType.IsObjectHandle() )
  6441. isConst = ctx->type.dataType.IsHandleToConst();
  6442. else
  6443. isConst = ctx->type.dataType.IsReadOnly();
  6444. // 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
  6445. // Find the correct method
  6446. asCArray<int> funcs;
  6447. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6448. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6449. {
  6450. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6451. if( func->name == opName &&
  6452. func->parameterTypes.GetLength() == 0 &&
  6453. (!isConst || func->isReadOnly) )
  6454. {
  6455. funcs.PushLast(func->id);
  6456. }
  6457. }
  6458. // Did we find the method?
  6459. if( funcs.GetLength() == 1 )
  6460. {
  6461. asCTypeInfo objType = ctx->type;
  6462. asCArray<asSExprContext *> args;
  6463. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6464. ReleaseTemporaryVariable(objType, &ctx->bc);
  6465. return 0;
  6466. }
  6467. else if( funcs.GetLength() == 0 )
  6468. {
  6469. asCString str;
  6470. str = asCString(opName) + "()";
  6471. if( isConst )
  6472. str += " const";
  6473. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6474. Error(str.AddressOf(), node);
  6475. ctx->type.SetDummy();
  6476. return -1;
  6477. }
  6478. else if( funcs.GetLength() > 1 )
  6479. {
  6480. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6481. PrintMatchingFuncs(funcs, node);
  6482. ctx->type.SetDummy();
  6483. return -1;
  6484. }
  6485. }
  6486. }
  6487. else if( op == ttPlus || op == ttMinus )
  6488. {
  6489. ProcessPropertyGetAccessor(ctx, node);
  6490. asCDataType to = ctx->type.dataType;
  6491. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  6492. if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
  6493. {
  6494. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6495. to = asCDataType::CreatePrimitive(ttInt8, false);
  6496. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6497. to = asCDataType::CreatePrimitive(ttInt16, false);
  6498. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6499. to = asCDataType::CreatePrimitive(ttInt, false);
  6500. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6501. to = asCDataType::CreatePrimitive(ttInt64, false);
  6502. else
  6503. {
  6504. Error(TXT_INVALID_TYPE, node);
  6505. return -1;
  6506. }
  6507. }
  6508. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6509. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6510. if( !ctx->type.isConstant )
  6511. {
  6512. ConvertToTempVariable(ctx);
  6513. asASSERT(!ctx->type.isLValue);
  6514. if( op == ttMinus )
  6515. {
  6516. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6517. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  6518. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6519. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  6520. else if( ctx->type.dataType.IsFloatType() )
  6521. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  6522. else if( ctx->type.dataType.IsDoubleType() )
  6523. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  6524. else
  6525. {
  6526. Error(TXT_ILLEGAL_OPERATION, node);
  6527. return -1;
  6528. }
  6529. return 0;
  6530. }
  6531. }
  6532. else
  6533. {
  6534. if( op == ttMinus )
  6535. {
  6536. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6537. ctx->type.intValue = -ctx->type.intValue;
  6538. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6539. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  6540. else if( ctx->type.dataType.IsFloatType() )
  6541. ctx->type.floatValue = -ctx->type.floatValue;
  6542. else if( ctx->type.dataType.IsDoubleType() )
  6543. ctx->type.doubleValue = -ctx->type.doubleValue;
  6544. else
  6545. {
  6546. Error(TXT_ILLEGAL_OPERATION, node);
  6547. return -1;
  6548. }
  6549. return 0;
  6550. }
  6551. }
  6552. if( op == ttPlus )
  6553. {
  6554. if( !ctx->type.dataType.IsIntegerType() &&
  6555. !ctx->type.dataType.IsFloatType() &&
  6556. !ctx->type.dataType.IsDoubleType() )
  6557. {
  6558. Error(TXT_ILLEGAL_OPERATION, node);
  6559. return -1;
  6560. }
  6561. }
  6562. }
  6563. else if( op == ttNot )
  6564. {
  6565. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6566. {
  6567. if( ctx->type.isConstant )
  6568. {
  6569. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  6570. return 0;
  6571. }
  6572. ProcessPropertyGetAccessor(ctx, node);
  6573. ConvertToTempVariable(ctx);
  6574. asASSERT(!ctx->type.isLValue);
  6575. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  6576. }
  6577. else
  6578. {
  6579. Error(TXT_ILLEGAL_OPERATION, node);
  6580. return -1;
  6581. }
  6582. }
  6583. else if( op == ttBitNot )
  6584. {
  6585. ProcessPropertyGetAccessor(ctx, node);
  6586. asCDataType to = ctx->type.dataType;
  6587. if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
  6588. {
  6589. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6590. to = asCDataType::CreatePrimitive(ttUInt8, false);
  6591. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6592. to = asCDataType::CreatePrimitive(ttUInt16, false);
  6593. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6594. to = asCDataType::CreatePrimitive(ttUInt, false);
  6595. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6596. to = asCDataType::CreatePrimitive(ttUInt64, false);
  6597. else
  6598. {
  6599. Error(TXT_INVALID_TYPE, node);
  6600. return -1;
  6601. }
  6602. }
  6603. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6604. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6605. if( ctx->type.dataType.IsUnsignedType() )
  6606. {
  6607. if( ctx->type.isConstant )
  6608. {
  6609. ctx->type.qwordValue = ~ctx->type.qwordValue;
  6610. return 0;
  6611. }
  6612. ConvertToTempVariable(ctx);
  6613. asASSERT(!ctx->type.isLValue);
  6614. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6615. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  6616. else
  6617. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  6618. }
  6619. else
  6620. {
  6621. Error(TXT_ILLEGAL_OPERATION, node);
  6622. return -1;
  6623. }
  6624. }
  6625. else if( op == ttInc || op == ttDec )
  6626. {
  6627. // Need a reference to the primitive that will be updated
  6628. // The result of this expression is the same reference as before
  6629. // Make sure the reference isn't a temporary variable
  6630. if( ctx->type.isTemporary )
  6631. {
  6632. Error(TXT_REF_IS_TEMP, node);
  6633. return -1;
  6634. }
  6635. if( ctx->type.dataType.IsReadOnly() )
  6636. {
  6637. Error(TXT_REF_IS_READ_ONLY, node);
  6638. return -1;
  6639. }
  6640. if( ctx->property_get || ctx->property_set )
  6641. {
  6642. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6643. return -1;
  6644. }
  6645. if( !ctx->type.isLValue )
  6646. {
  6647. Error(TXT_NOT_LVALUE, node);
  6648. return -1;
  6649. }
  6650. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6651. ConvertToReference(ctx);
  6652. else if( !ctx->type.dataType.IsReference() )
  6653. {
  6654. Error(TXT_NOT_VALID_REFERENCE, node);
  6655. return -1;
  6656. }
  6657. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6658. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6659. {
  6660. if( op == ttInc )
  6661. ctx->bc.Instr(asBC_INCi64);
  6662. else
  6663. ctx->bc.Instr(asBC_DECi64);
  6664. }
  6665. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  6666. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  6667. {
  6668. if( op == ttInc )
  6669. ctx->bc.Instr(asBC_INCi);
  6670. else
  6671. ctx->bc.Instr(asBC_DECi);
  6672. }
  6673. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6674. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6675. {
  6676. if( op == ttInc )
  6677. ctx->bc.Instr(asBC_INCi16);
  6678. else
  6679. ctx->bc.Instr(asBC_DECi16);
  6680. }
  6681. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6682. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6683. {
  6684. if( op == ttInc )
  6685. ctx->bc.Instr(asBC_INCi8);
  6686. else
  6687. ctx->bc.Instr(asBC_DECi8);
  6688. }
  6689. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  6690. {
  6691. if( op == ttInc )
  6692. ctx->bc.Instr(asBC_INCf);
  6693. else
  6694. ctx->bc.Instr(asBC_DECf);
  6695. }
  6696. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  6697. {
  6698. if( op == ttInc )
  6699. ctx->bc.Instr(asBC_INCd);
  6700. else
  6701. ctx->bc.Instr(asBC_DECd);
  6702. }
  6703. else
  6704. {
  6705. Error(TXT_ILLEGAL_OPERATION, node);
  6706. return -1;
  6707. }
  6708. }
  6709. else
  6710. {
  6711. // Unknown operator
  6712. asASSERT(false);
  6713. return -1;
  6714. }
  6715. return 0;
  6716. }
  6717. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  6718. {
  6719. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6720. {
  6721. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  6722. ctx->type.dataType.MakeReference(true);
  6723. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  6724. }
  6725. }
  6726. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, bool isThisAccess)
  6727. {
  6728. return FindPropertyAccessor(name, ctx, 0, node, isThisAccess);
  6729. }
  6730. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, bool isThisAccess)
  6731. {
  6732. if( engine->ep.propertyAccessorMode == 0 )
  6733. {
  6734. // Property accessors have been disabled by the application
  6735. return 0;
  6736. }
  6737. int getId = 0, setId = 0;
  6738. asCString getName = "get_" + name;
  6739. asCString setName = "set_" + name;
  6740. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  6741. if( ctx->type.dataType.IsObject() )
  6742. {
  6743. // Check if the object has any methods with the property name prefixed by get_ or set_
  6744. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6745. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6746. {
  6747. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  6748. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6749. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  6750. {
  6751. if( getId == 0 )
  6752. getId = ot->methods[n];
  6753. else
  6754. {
  6755. if( multipleGetFuncs.GetLength() == 0 )
  6756. multipleGetFuncs.PushLast(getId);
  6757. multipleGetFuncs.PushLast(ot->methods[n]);
  6758. }
  6759. }
  6760. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6761. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  6762. {
  6763. if( setId == 0 )
  6764. setId = ot->methods[n];
  6765. else
  6766. {
  6767. if( multipleSetFuncs.GetLength() == 0 )
  6768. multipleSetFuncs.PushLast(setId);
  6769. multipleSetFuncs.PushLast(ot->methods[n]);
  6770. }
  6771. }
  6772. }
  6773. }
  6774. else
  6775. {
  6776. // Look for appropriate global functions.
  6777. asCArray<int> funcs;
  6778. asUINT n;
  6779. builder->GetFunctionDescriptions(getName.AddressOf(), funcs);
  6780. for( n = 0; n < funcs.GetLength(); n++ )
  6781. {
  6782. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6783. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6784. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  6785. {
  6786. if( getId == 0 )
  6787. getId = funcs[n];
  6788. else
  6789. {
  6790. if( multipleGetFuncs.GetLength() == 0 )
  6791. multipleGetFuncs.PushLast(getId);
  6792. multipleGetFuncs.PushLast(funcs[n]);
  6793. }
  6794. }
  6795. }
  6796. funcs.SetLength(0);
  6797. builder->GetFunctionDescriptions(setName.AddressOf(), funcs);
  6798. for( n = 0; n < funcs.GetLength(); n++ )
  6799. {
  6800. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6801. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6802. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  6803. {
  6804. if( setId == 0 )
  6805. setId = funcs[n];
  6806. else
  6807. {
  6808. if( multipleSetFuncs.GetLength() == 0 )
  6809. multipleSetFuncs.PushLast(getId);
  6810. multipleSetFuncs.PushLast(funcs[n]);
  6811. }
  6812. }
  6813. }
  6814. }
  6815. // Check for multiple matches
  6816. if( multipleGetFuncs.GetLength() > 0 )
  6817. {
  6818. asCString str;
  6819. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  6820. Error(str.AddressOf(), node);
  6821. PrintMatchingFuncs(multipleGetFuncs, node);
  6822. return -1;
  6823. }
  6824. if( multipleSetFuncs.GetLength() > 0 )
  6825. {
  6826. asCString str;
  6827. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  6828. Error(str.AddressOf(), node);
  6829. PrintMatchingFuncs(multipleSetFuncs, node);
  6830. return -1;
  6831. }
  6832. // Check for type compatibility between get and set accessor
  6833. if( getId && setId )
  6834. {
  6835. asCScriptFunction *getFunc = engine->scriptFunctions[getId];
  6836. asCScriptFunction *setFunc = engine->scriptFunctions[setId];
  6837. // It is permitted for a getter to return a handle and the setter to take a reference
  6838. int idx = (arg?1:0);
  6839. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  6840. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  6841. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  6842. {
  6843. asCString str;
  6844. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  6845. Error(str.AddressOf(), node);
  6846. asCArray<int> funcs;
  6847. funcs.PushLast(getId);
  6848. funcs.PushLast(setId);
  6849. PrintMatchingFuncs(funcs, node);
  6850. return -1;
  6851. }
  6852. }
  6853. // Check if we are within one of the accessors
  6854. int realGetId = getId;
  6855. int realSetId = setId;
  6856. if( outFunc->objectType && isThisAccess )
  6857. {
  6858. // The property accessors would be virtual functions, so we need to find the real implementation
  6859. asCScriptFunction *getFunc = getId ? engine->scriptFunctions[getId] : 0;
  6860. if( getFunc &&
  6861. getFunc->funcType == asFUNC_VIRTUAL &&
  6862. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  6863. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  6864. asCScriptFunction *setFunc = setId ? engine->scriptFunctions[setId] : 0;
  6865. if( setFunc &&
  6866. setFunc->funcType == asFUNC_VIRTUAL &&
  6867. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  6868. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  6869. }
  6870. // Avoid recursive call, by not treating this as a property accessor call.
  6871. // This will also allow having the real property with the same name as the accessors.
  6872. if( (isThisAccess || outFunc->objectType == 0) &&
  6873. ((realGetId && realGetId == outFunc->id) ||
  6874. (realSetId && realSetId == outFunc->id)) )
  6875. {
  6876. getId = 0;
  6877. setId = 0;
  6878. }
  6879. // Check if the application has disabled script written property accessors
  6880. if( engine->ep.propertyAccessorMode == 1 )
  6881. {
  6882. if( getId && engine->scriptFunctions[getId]->funcType != asFUNC_SYSTEM )
  6883. getId = 0;
  6884. if( setId && engine->scriptFunctions[setId]->funcType != asFUNC_SYSTEM )
  6885. setId = 0;
  6886. }
  6887. if( getId || setId )
  6888. {
  6889. // Property accessors were found, but we don't know which is to be used yet, so
  6890. // we just prepare the bytecode for the method call, and then store the function ids
  6891. // so that the right one can be used when we get there.
  6892. ctx->property_get = getId;
  6893. ctx->property_set = setId;
  6894. if( ctx->type.dataType.IsObject() )
  6895. {
  6896. // If the object is read-only then we need to remember that
  6897. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  6898. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  6899. ctx->property_const = true;
  6900. else
  6901. ctx->property_const = false;
  6902. // If the object is a handle then we need to remember that
  6903. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  6904. ctx->property_ref = ctx->type.dataType.IsReference();
  6905. }
  6906. // The setter's parameter type is used as the property type,
  6907. // unless only the getter is available
  6908. asCDataType dt;
  6909. if( setId )
  6910. dt = engine->scriptFunctions[setId]->parameterTypes[(arg?1:0)];
  6911. else
  6912. dt = engine->scriptFunctions[getId]->returnType;
  6913. // Just change the type, the context must still maintain information
  6914. // about previous variable offset and the indicator of temporary variable.
  6915. int offset = ctx->type.stackOffset;
  6916. bool isTemp = ctx->type.isTemporary;
  6917. ctx->type.Set(dt);
  6918. ctx->type.stackOffset = (short)offset;
  6919. ctx->type.isTemporary = isTemp;
  6920. ctx->exprNode = node;
  6921. // Store the argument for later use
  6922. if( arg )
  6923. {
  6924. ctx->property_arg = asNEW(asSExprContext)(engine);
  6925. MergeExprBytecodeAndType(ctx->property_arg, arg);
  6926. }
  6927. return 1;
  6928. }
  6929. // No accessor was found
  6930. return 0;
  6931. }
  6932. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  6933. {
  6934. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  6935. if( !ctx->property_set )
  6936. {
  6937. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  6938. return -1;
  6939. }
  6940. asCTypeInfo objType = ctx->type;
  6941. asCScriptFunction *func = engine->scriptFunctions[ctx->property_set];
  6942. // Make sure the arg match the property
  6943. asCArray<int> funcs;
  6944. funcs.PushLast(ctx->property_set);
  6945. asCArray<asSExprContext *> args;
  6946. if( ctx->property_arg )
  6947. args.PushLast(ctx->property_arg);
  6948. args.PushLast(arg);
  6949. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  6950. if( funcs.GetLength() == 0 )
  6951. {
  6952. // MatchFunctions already reported the error
  6953. if( ctx->property_arg )
  6954. {
  6955. asDELETE(ctx->property_arg, asSExprContext);
  6956. ctx->property_arg = 0;
  6957. }
  6958. return -1;
  6959. }
  6960. if( func->objectType )
  6961. {
  6962. // Setup the context with the original type so the method call gets built correctly
  6963. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6964. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6965. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6966. // Don't allow the call if the object is read-only and the property accessor is not const
  6967. if( ctx->property_const && !func->isReadOnly )
  6968. {
  6969. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  6970. asCArray<int> funcs;
  6971. funcs.PushLast(ctx->property_set);
  6972. PrintMatchingFuncs(funcs, node);
  6973. }
  6974. }
  6975. // Call the accessor
  6976. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  6977. if( func->objectType )
  6978. {
  6979. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  6980. if( objType.isTemporary &&
  6981. ctx->type.dataType.IsReference() &&
  6982. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6983. {
  6984. // Remember the original object's variable, so that it can be released
  6985. // later on when the reference to its member goes out of scope
  6986. ctx->type.isTemporary = true;
  6987. ctx->type.stackOffset = objType.stackOffset;
  6988. }
  6989. else
  6990. {
  6991. // As the method didn't return a reference to a member
  6992. // we can safely release the original object now
  6993. ReleaseTemporaryVariable(objType, &ctx->bc);
  6994. }
  6995. }
  6996. ctx->property_get = 0;
  6997. ctx->property_set = 0;
  6998. if( ctx->property_arg )
  6999. {
  7000. asDELETE(ctx->property_arg, asSExprContext);
  7001. ctx->property_arg = 0;
  7002. }
  7003. return 0;
  7004. }
  7005. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  7006. {
  7007. // If no property accessor has been prepared then don't do anything
  7008. if( !ctx->property_get && !ctx->property_set )
  7009. return;
  7010. if( !ctx->property_get )
  7011. {
  7012. // Raise error on missing accessor
  7013. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  7014. ctx->type.SetDummy();
  7015. return;
  7016. }
  7017. asCTypeInfo objType = ctx->type;
  7018. asCScriptFunction *func = engine->scriptFunctions[ctx->property_get];
  7019. // Make sure the arg match the property
  7020. asCArray<int> funcs;
  7021. funcs.PushLast(ctx->property_get);
  7022. asCArray<asSExprContext *> args;
  7023. if( ctx->property_arg )
  7024. args.PushLast(ctx->property_arg);
  7025. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7026. if( funcs.GetLength() == 0 )
  7027. {
  7028. // MatchFunctions already reported the error
  7029. if( ctx->property_arg )
  7030. {
  7031. asDELETE(ctx->property_arg, asSExprContext);
  7032. ctx->property_arg = 0;
  7033. }
  7034. ctx->type.SetDummy();
  7035. return;
  7036. }
  7037. if( func->objectType )
  7038. {
  7039. // Setup the context with the original type so the method call gets built correctly
  7040. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7041. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7042. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7043. // Don't allow the call if the object is read-only and the property accessor is not const
  7044. if( ctx->property_const && !func->isReadOnly )
  7045. {
  7046. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7047. asCArray<int> funcs;
  7048. funcs.PushLast(ctx->property_get);
  7049. PrintMatchingFuncs(funcs, node);
  7050. }
  7051. }
  7052. // Call the accessor
  7053. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  7054. if( func->objectType )
  7055. {
  7056. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  7057. if( objType.isTemporary &&
  7058. ctx->type.dataType.IsReference() &&
  7059. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7060. {
  7061. // Remember the original object's variable, so that it can be released
  7062. // later on when the reference to its member goes out of scope
  7063. ctx->type.isTemporary = true;
  7064. ctx->type.stackOffset = objType.stackOffset;
  7065. }
  7066. else
  7067. {
  7068. // As the method didn't return a reference to a member
  7069. // we can safely release the original object now
  7070. ReleaseTemporaryVariable(objType, &ctx->bc);
  7071. }
  7072. }
  7073. ctx->property_get = 0;
  7074. ctx->property_set = 0;
  7075. if( ctx->property_arg )
  7076. {
  7077. asDELETE(ctx->property_arg, asSExprContext);
  7078. ctx->property_arg = 0;
  7079. }
  7080. }
  7081. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  7082. {
  7083. int op = node->tokenType;
  7084. // Check if the variable is initialized (if it indeed is a variable)
  7085. IsVariableInitialized(&ctx->type, node);
  7086. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7087. {
  7088. const char *opName = 0;
  7089. switch( op )
  7090. {
  7091. case ttInc: opName = "opPostInc"; break;
  7092. case ttDec: opName = "opPostDec"; break;
  7093. }
  7094. if( opName )
  7095. {
  7096. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7097. ProcessPropertyGetAccessor(ctx, node);
  7098. // Is it a const value?
  7099. bool isConst = false;
  7100. if( ctx->type.dataType.IsObjectHandle() )
  7101. isConst = ctx->type.dataType.IsHandleToConst();
  7102. else
  7103. isConst = ctx->type.dataType.IsReadOnly();
  7104. // 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
  7105. // Find the correct method
  7106. asCArray<int> funcs;
  7107. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7108. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7109. {
  7110. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7111. if( func->name == opName &&
  7112. func->parameterTypes.GetLength() == 0 &&
  7113. (!isConst || func->isReadOnly) )
  7114. {
  7115. funcs.PushLast(func->id);
  7116. }
  7117. }
  7118. // Did we find the method?
  7119. if( funcs.GetLength() == 1 )
  7120. {
  7121. asCTypeInfo objType = ctx->type;
  7122. asCArray<asSExprContext *> args;
  7123. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7124. ReleaseTemporaryVariable(objType, &ctx->bc);
  7125. return 0;
  7126. }
  7127. else if( funcs.GetLength() == 0 )
  7128. {
  7129. asCString str;
  7130. str = asCString(opName) + "()";
  7131. if( isConst )
  7132. str += " const";
  7133. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7134. Error(str.AddressOf(), node);
  7135. ctx->type.SetDummy();
  7136. return -1;
  7137. }
  7138. else if( funcs.GetLength() > 1 )
  7139. {
  7140. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7141. PrintMatchingFuncs(funcs, node);
  7142. ctx->type.SetDummy();
  7143. return -1;
  7144. }
  7145. }
  7146. }
  7147. else if( op == ttInc || op == ttDec )
  7148. {
  7149. // Make sure the reference isn't a temporary variable
  7150. if( ctx->type.isTemporary )
  7151. {
  7152. Error(TXT_REF_IS_TEMP, node);
  7153. return -1;
  7154. }
  7155. if( ctx->type.dataType.IsReadOnly() )
  7156. {
  7157. Error(TXT_REF_IS_READ_ONLY, node);
  7158. return -1;
  7159. }
  7160. if( ctx->property_get || ctx->property_set )
  7161. {
  7162. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7163. return -1;
  7164. }
  7165. if( !ctx->type.isLValue )
  7166. {
  7167. Error(TXT_NOT_LVALUE, node);
  7168. return -1;
  7169. }
  7170. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7171. ConvertToReference(ctx);
  7172. else if( !ctx->type.dataType.IsReference() )
  7173. {
  7174. Error(TXT_NOT_VALID_REFERENCE, node);
  7175. return -1;
  7176. }
  7177. // Copy the value to a temp before changing it
  7178. ConvertToTempVariable(ctx);
  7179. asASSERT(!ctx->type.isLValue);
  7180. // Increment the value pointed to by the reference still in the register
  7181. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  7182. if( ctx->type.dataType.IsDoubleType() )
  7183. {
  7184. iInc = asBC_INCd;
  7185. iDec = asBC_DECd;
  7186. }
  7187. else if( ctx->type.dataType.IsFloatType() )
  7188. {
  7189. iInc = asBC_INCf;
  7190. iDec = asBC_DECf;
  7191. }
  7192. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  7193. {
  7194. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7195. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7196. {
  7197. iInc = asBC_INCi16;
  7198. iDec = asBC_DECi16;
  7199. }
  7200. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7201. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7202. {
  7203. iInc = asBC_INCi8;
  7204. iDec = asBC_DECi8;
  7205. }
  7206. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7207. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7208. {
  7209. iInc = asBC_INCi64;
  7210. iDec = asBC_DECi64;
  7211. }
  7212. }
  7213. else
  7214. {
  7215. Error(TXT_ILLEGAL_OPERATION, node);
  7216. return -1;
  7217. }
  7218. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  7219. }
  7220. else if( op == ttDot )
  7221. {
  7222. if( node->firstChild->nodeType == snIdentifier )
  7223. {
  7224. ProcessPropertyGetAccessor(ctx, node);
  7225. // Get the property name
  7226. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  7227. // We need to look for get/set property accessors.
  7228. // If found, the context stores information on the get/set accessors
  7229. // until it is known which is to be used.
  7230. int r = 0;
  7231. if( node->next && node->next->tokenType == ttOpenBracket )
  7232. {
  7233. // The property accessor should take an index arg
  7234. asSExprContext dummyArg(engine);
  7235. r = FindPropertyAccessor(name, ctx, &dummyArg, node);
  7236. }
  7237. if( r == 0 )
  7238. r = FindPropertyAccessor(name, ctx, node);
  7239. if( r != 0 )
  7240. return r;
  7241. if( !ctx->type.dataType.IsPrimitive() )
  7242. Dereference(ctx, true);
  7243. if( ctx->type.dataType.IsObjectHandle() )
  7244. {
  7245. // Convert the handle to a normal object
  7246. asCDataType dt = ctx->type.dataType;
  7247. dt.MakeHandle(false);
  7248. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  7249. // The handle may not have been an lvalue, but the dereferenced object is
  7250. ctx->type.isLValue = true;
  7251. }
  7252. // Find the property offset and type
  7253. if( ctx->type.dataType.IsObject() )
  7254. {
  7255. bool isConst = ctx->type.dataType.IsReadOnly();
  7256. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  7257. if( prop )
  7258. {
  7259. // Is the property access allowed?
  7260. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  7261. {
  7262. asCString msg;
  7263. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  7264. Error(msg.AddressOf(), node);
  7265. }
  7266. // Put the offset on the stack
  7267. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  7268. if( prop->type.IsReference() )
  7269. ctx->bc.Instr(asBC_RDSPTR);
  7270. // Reference to primitive must be stored in the temp register
  7271. if( prop->type.IsPrimitive() )
  7272. {
  7273. ctx->bc.Instr(asBC_PopRPtr);
  7274. }
  7275. // Set the new type (keeping info about temp variable)
  7276. ctx->type.dataType = prop->type;
  7277. ctx->type.dataType.MakeReference(true);
  7278. ctx->type.isVariable = false;
  7279. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7280. {
  7281. // Objects that are members are not references
  7282. ctx->type.dataType.MakeReference(false);
  7283. }
  7284. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  7285. }
  7286. else
  7287. {
  7288. asCString str;
  7289. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7290. Error(str.AddressOf(), node);
  7291. return -1;
  7292. }
  7293. }
  7294. else
  7295. {
  7296. asCString str;
  7297. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7298. Error(str.AddressOf(), node);
  7299. return -1;
  7300. }
  7301. }
  7302. else
  7303. {
  7304. // Make sure it is an object we are accessing
  7305. if( !ctx->type.dataType.IsObject() )
  7306. {
  7307. asCString str;
  7308. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  7309. Error(str.AddressOf(), node);
  7310. return -1;
  7311. }
  7312. // Process the get property accessor
  7313. ProcessPropertyGetAccessor(ctx, node);
  7314. bool isConst = false;
  7315. if( ctx->type.dataType.IsObjectHandle() )
  7316. isConst = ctx->type.dataType.IsHandleToConst();
  7317. else
  7318. isConst = ctx->type.dataType.IsReadOnly();
  7319. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  7320. asCTypeInfo objType = ctx->type;
  7321. // Compile function call
  7322. CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  7323. // If the method returned a reference, then we can't release the original
  7324. // object yet, because the reference may be to a member of it
  7325. if( objType.isTemporary &&
  7326. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7327. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7328. {
  7329. // Remember the original object's variable, so that it can be released
  7330. // later on when the reference to its member goes out of scope
  7331. ctx->type.isTemporary = true;
  7332. ctx->type.stackOffset = objType.stackOffset;
  7333. }
  7334. else
  7335. {
  7336. // As the method didn't return a reference to a member
  7337. // we can safely release the original object now
  7338. ReleaseTemporaryVariable(objType, &ctx->bc);
  7339. }
  7340. }
  7341. }
  7342. else if( op == ttOpenBracket )
  7343. {
  7344. // If the property access takes an index arg, then we should use that instead of processing it now
  7345. asCString propertyName;
  7346. if( (ctx->property_get && engine->scriptFunctions[ctx->property_get]->GetParamCount() == 1) ||
  7347. (ctx->property_set && engine->scriptFunctions[ctx->property_set]->GetParamCount() == 2) )
  7348. {
  7349. // Determine the name of the property accessor
  7350. asCScriptFunction *func = 0;
  7351. if( ctx->property_get )
  7352. func = engine->scriptFunctions[ctx->property_get];
  7353. else
  7354. func = engine->scriptFunctions[ctx->property_set];
  7355. propertyName = func->GetName();
  7356. propertyName = propertyName.SubString(4);
  7357. // Set the original type of the expression so we can re-evaluate the property accessor
  7358. if( func->objectType )
  7359. {
  7360. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7361. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7362. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7363. }
  7364. ctx->property_get = ctx->property_set = 0;
  7365. if( ctx->property_arg )
  7366. {
  7367. asDELETE(ctx->property_arg, asSExprContext);
  7368. ctx->property_arg = 0;
  7369. }
  7370. }
  7371. else
  7372. {
  7373. if( !ctx->type.dataType.IsObject() )
  7374. {
  7375. asCString str;
  7376. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7377. Error(str.AddressOf(), node);
  7378. return -1;
  7379. }
  7380. ProcessPropertyGetAccessor(ctx, node);
  7381. }
  7382. Dereference(ctx, true);
  7383. // Compile the expression
  7384. asSExprContext expr(engine);
  7385. CompileAssignment(node->firstChild, &expr);
  7386. // Check for the existence of the opIndex method
  7387. asSExprContext lctx(engine);
  7388. MergeExprBytecodeAndType(&lctx, ctx);
  7389. int r = 0;
  7390. if( propertyName == "" )
  7391. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  7392. if( r == 0 )
  7393. {
  7394. // Check for accessors methods for the opIndex
  7395. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node);
  7396. if( r == 0 )
  7397. {
  7398. asCString str;
  7399. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7400. Error(str.AddressOf(), node);
  7401. return -1;
  7402. }
  7403. else if( r < 0 )
  7404. return -1;
  7405. MergeExprBytecodeAndType(ctx, &lctx);
  7406. }
  7407. }
  7408. return 0;
  7409. }
  7410. int asCCompiler::GetPrecedence(asCScriptNode *op)
  7411. {
  7412. // x * y, x / y, x % y
  7413. // x + y, x - y
  7414. // x <= y, x < y, x >= y, x > y
  7415. // x = =y, x != y, x xor y, x is y, x !is y
  7416. // x and y
  7417. // x or y
  7418. // The following are not used in this function,
  7419. // but should have lower precedence than the above
  7420. // x ? y : z
  7421. // x = y
  7422. // The expression term have the highest precedence
  7423. if( op->nodeType == snExprTerm )
  7424. return 1;
  7425. // Evaluate operators by token
  7426. int tokenType = op->tokenType;
  7427. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  7428. return 0;
  7429. if( tokenType == ttPlus || tokenType == ttMinus )
  7430. return -1;
  7431. if( tokenType == ttBitShiftLeft ||
  7432. tokenType == ttBitShiftRight ||
  7433. tokenType == ttBitShiftRightArith )
  7434. return -2;
  7435. if( tokenType == ttAmp )
  7436. return -3;
  7437. if( tokenType == ttBitXor )
  7438. return -4;
  7439. if( tokenType == ttBitOr )
  7440. return -5;
  7441. if( tokenType == ttLessThanOrEqual ||
  7442. tokenType == ttLessThan ||
  7443. tokenType == ttGreaterThanOrEqual ||
  7444. tokenType == ttGreaterThan )
  7445. return -6;
  7446. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  7447. return -7;
  7448. if( tokenType == ttAnd )
  7449. return -8;
  7450. if( tokenType == ttOr )
  7451. return -9;
  7452. // Unknown operator
  7453. asASSERT(false);
  7454. return 0;
  7455. }
  7456. int asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<int> &matches, const asCTypeInfo *argType, int paramNum, bool allowObjectConstruct)
  7457. {
  7458. bool isExactMatch = false;
  7459. bool isMatchExceptConst = false;
  7460. bool isMatchWithBaseType = false;
  7461. bool isMatchExceptSign = false;
  7462. bool isMatchNotVarType = false;
  7463. asUINT n;
  7464. matches.SetLength(0);
  7465. for( n = 0; n < funcs.GetLength(); n++ )
  7466. {
  7467. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  7468. // Does the function have arguments enough?
  7469. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  7470. continue;
  7471. // Can we make the match by implicit conversion?
  7472. asSExprContext ti(engine);
  7473. ti.type = *argType;
  7474. if( argType->dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  7475. ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, 0, allowObjectConstruct);
  7476. // If the function parameter is an inout-reference then it must not be possible to call the
  7477. // function with an incorrect argument type, even though the type can normally be converted.
  7478. if( desc->parameterTypes[paramNum].IsReference() &&
  7479. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  7480. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7481. {
  7482. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  7483. desc->parameterTypes[paramNum].GetTokenType() != argType->dataType.GetTokenType() )
  7484. continue;
  7485. if( desc->parameterTypes[paramNum].IsEnumType() &&
  7486. desc->parameterTypes[paramNum].GetObjectType() != argType->dataType.GetObjectType() )
  7487. continue;
  7488. }
  7489. // How well does the argument match the function parameter?
  7490. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  7491. {
  7492. // Is it an exact match?
  7493. if( argType->dataType.IsEqualExceptRef(ti.type.dataType) )
  7494. {
  7495. if( !isExactMatch ) matches.SetLength(0);
  7496. isExactMatch = true;
  7497. matches.PushLast(funcs[n]);
  7498. continue;
  7499. }
  7500. if( !isExactMatch )
  7501. {
  7502. // Is it a match except const?
  7503. if( argType->dataType.IsEqualExceptRefAndConst(ti.type.dataType) )
  7504. {
  7505. if( !isMatchExceptConst ) matches.SetLength(0);
  7506. isMatchExceptConst = true;
  7507. matches.PushLast(funcs[n]);
  7508. continue;
  7509. }
  7510. if( !isMatchExceptConst )
  7511. {
  7512. // Is it a size promotion, e.g. int8 -> int?
  7513. if( argType->dataType.IsSamePrimitiveBaseType(ti.type.dataType) ||
  7514. (argType->dataType.IsEnumType() && ti.type.dataType.IsIntegerType()) )
  7515. {
  7516. if( !isMatchWithBaseType ) matches.SetLength(0);
  7517. isMatchWithBaseType = true;
  7518. matches.PushLast(funcs[n]);
  7519. continue;
  7520. }
  7521. if( !isMatchWithBaseType )
  7522. {
  7523. // Conversion between signed and unsigned integer is better than between integer and float
  7524. // Is it a match except for sign?
  7525. if( (argType->dataType.IsIntegerType() && ti.type.dataType.IsUnsignedType()) ||
  7526. (argType->dataType.IsUnsignedType() && ti.type.dataType.IsIntegerType()) ||
  7527. (argType->dataType.IsEnumType() && ti.type.dataType.IsUnsignedType()) )
  7528. {
  7529. if( !isMatchExceptSign ) matches.SetLength(0);
  7530. isMatchExceptSign = true;
  7531. matches.PushLast(funcs[n]);
  7532. continue;
  7533. }
  7534. if( !isMatchExceptSign )
  7535. {
  7536. // If there was any match without a var type it has higher priority
  7537. if( desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7538. {
  7539. if( !isMatchNotVarType ) matches.SetLength(0);
  7540. isMatchNotVarType = true;
  7541. matches.PushLast(funcs[n]);
  7542. continue;
  7543. }
  7544. // Implicit conversion to ?& has the smallest priority
  7545. if( !isMatchNotVarType )
  7546. matches.PushLast(funcs[n]);
  7547. }
  7548. }
  7549. }
  7550. }
  7551. }
  7552. }
  7553. return (int)matches.GetLength();
  7554. }
  7555. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, asCArray<int> *reservedVars)
  7556. {
  7557. // Reference parameters whose value won't be used don't evaluate the expression
  7558. if( paramType->IsReference() && !(refType & asTM_INREF) )
  7559. {
  7560. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  7561. asSExprContext *orig = asNEW(asSExprContext)(engine);
  7562. MergeExprBytecodeAndType(orig, arg);
  7563. arg->origExpr = orig;
  7564. }
  7565. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, reservedVars);
  7566. // arg still holds the original expression for output parameters
  7567. ctx->bc.AddCode(&arg->bc);
  7568. }
  7569. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7570. {
  7571. ctx->exprNode = node;
  7572. // What type of operator is it?
  7573. int token = node->tokenType;
  7574. if( token == ttUnrecognizedToken )
  7575. {
  7576. // This happens when the compiler is inferring an assignment
  7577. // operation from another action, for example in preparing a value
  7578. // as a function argument
  7579. token = ttAssignment;
  7580. }
  7581. // boolean operators are not overloadable
  7582. if( token == ttAnd ||
  7583. token == ttOr ||
  7584. token == ttXor )
  7585. return false;
  7586. // Dual operators can also be implemented as class methods
  7587. if( token == ttEqual ||
  7588. token == ttNotEqual )
  7589. {
  7590. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7591. // Find the matching opEquals method
  7592. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7593. if( r == 0 )
  7594. {
  7595. // Try again by switching the order of the operands
  7596. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7597. }
  7598. if( r == 1 )
  7599. {
  7600. if( token == ttNotEqual )
  7601. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7602. // Success, don't continue
  7603. return true;
  7604. }
  7605. else if( r < 0 )
  7606. {
  7607. // Compiler error, don't continue
  7608. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7609. return true;
  7610. }
  7611. }
  7612. if( token == ttEqual ||
  7613. token == ttNotEqual ||
  7614. token == ttLessThan ||
  7615. token == ttLessThanOrEqual ||
  7616. token == ttGreaterThan ||
  7617. token == ttGreaterThanOrEqual )
  7618. {
  7619. bool swappedOrder = false;
  7620. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7621. // Find the matching opCmp method
  7622. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7623. if( r == 0 )
  7624. {
  7625. // Try again by switching the order of the operands
  7626. swappedOrder = true;
  7627. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7628. }
  7629. if( r == 1 )
  7630. {
  7631. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7632. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  7633. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  7634. if( token == ttEqual )
  7635. ctx->bc.Instr(asBC_TZ);
  7636. else if( token == ttNotEqual )
  7637. ctx->bc.Instr(asBC_TNZ);
  7638. else if( (token == ttLessThan && !swappedOrder) ||
  7639. (token == ttGreaterThan && swappedOrder) )
  7640. ctx->bc.Instr(asBC_TS);
  7641. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  7642. (token == ttGreaterThanOrEqual && swappedOrder) )
  7643. ctx->bc.Instr(asBC_TNP);
  7644. else if( (token == ttGreaterThan && !swappedOrder) ||
  7645. (token == ttLessThan && swappedOrder) )
  7646. ctx->bc.Instr(asBC_TP);
  7647. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  7648. (token == ttLessThanOrEqual && swappedOrder) )
  7649. ctx->bc.Instr(asBC_TNS);
  7650. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  7651. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  7652. // Success, don't continue
  7653. return true;
  7654. }
  7655. else if( r < 0 )
  7656. {
  7657. // Compiler error, don't continue
  7658. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7659. return true;
  7660. }
  7661. }
  7662. // The rest of the operators are not commutative, and doesn't require specific return type
  7663. const char *op = 0, *op_r = 0;
  7664. switch( token )
  7665. {
  7666. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  7667. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  7668. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  7669. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  7670. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  7671. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  7672. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  7673. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  7674. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  7675. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  7676. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  7677. }
  7678. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  7679. if( op && op_r )
  7680. {
  7681. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7682. // Find the matching operator method
  7683. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7684. if( r == 0 )
  7685. {
  7686. // Try again by switching the order of the operands, and using the reversed operator
  7687. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  7688. }
  7689. if( r == 1 )
  7690. {
  7691. // Success, don't continue
  7692. return true;
  7693. }
  7694. else if( r < 0 )
  7695. {
  7696. // Compiler error, don't continue
  7697. ctx->type.SetDummy();
  7698. return true;
  7699. }
  7700. }
  7701. // Assignment operators
  7702. op = 0;
  7703. switch( token )
  7704. {
  7705. case ttAssignment: op = "opAssign"; break;
  7706. case ttAddAssign: op = "opAddAssign"; break;
  7707. case ttSubAssign: op = "opSubAssign"; break;
  7708. case ttMulAssign: op = "opMulAssign"; break;
  7709. case ttDivAssign: op = "opDivAssign"; break;
  7710. case ttModAssign: op = "opModAssign"; break;
  7711. case ttOrAssign: op = "opOrAssign"; break;
  7712. case ttAndAssign: op = "opAndAssign"; break;
  7713. case ttXorAssign: op = "opXorAssign"; break;
  7714. case ttShiftLeftAssign: op = "opShlAssign"; break;
  7715. case ttShiftRightLAssign: op = "opShrAssign"; break;
  7716. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  7717. }
  7718. if( op )
  7719. {
  7720. // TODO: Shouldn't accept const lvalue with the assignment operators
  7721. // Find the matching operator method
  7722. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7723. if( r == 1 )
  7724. {
  7725. // Success, don't continue
  7726. return true;
  7727. }
  7728. else if( r < 0 )
  7729. {
  7730. // Compiler error, don't continue
  7731. ctx->type.SetDummy();
  7732. return true;
  7733. }
  7734. }
  7735. // No suitable operator was found
  7736. return false;
  7737. }
  7738. // Returns negative on compile error
  7739. // zero on no matching operator
  7740. // one on matching operator
  7741. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  7742. {
  7743. // Find the matching method
  7744. if( lctx->type.dataType.IsObject() &&
  7745. (!lctx->type.isExplicitHandle ||
  7746. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  7747. {
  7748. // Is the left value a const?
  7749. bool isConst = false;
  7750. if( lctx->type.dataType.IsObjectHandle() )
  7751. isConst = lctx->type.dataType.IsHandleToConst();
  7752. else
  7753. isConst = lctx->type.dataType.IsReadOnly();
  7754. asCArray<int> funcs;
  7755. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  7756. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7757. {
  7758. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7759. if( func->name == methodName &&
  7760. (!specificReturn || func->returnType == returnType) &&
  7761. func->parameterTypes.GetLength() == 1 &&
  7762. (!isConst || func->isReadOnly) )
  7763. {
  7764. // Make sure the method is accessible by the module
  7765. if( builder->module->accessMask & func->accessMask )
  7766. {
  7767. #ifdef AS_DEPRECATED
  7768. // deprecated since 2011-10-04
  7769. asCConfigGroup *group = engine->FindConfigGroupForFunction(func->id);
  7770. if( !group || group->HasModuleAccess(builder->module->name.AddressOf()) )
  7771. #endif
  7772. funcs.PushLast(func->id);
  7773. }
  7774. }
  7775. }
  7776. // Which is the best matching function?
  7777. asCArray<int> ops;
  7778. MatchArgument(funcs, ops, &rctx->type, 0);
  7779. // If the object is not const, then we need to prioritize non-const methods
  7780. if( !isConst )
  7781. FilterConst(ops);
  7782. // Did we find an operator?
  7783. if( ops.GetLength() == 1 )
  7784. {
  7785. // Process the lctx expression as get accessor
  7786. ProcessPropertyGetAccessor(lctx, node);
  7787. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  7788. asCTypeInfo objType = lctx->type;
  7789. asCArray<asSExprContext *> args;
  7790. args.PushLast(rctx);
  7791. MergeExprBytecode(ctx, lctx);
  7792. ctx->type = lctx->type;
  7793. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  7794. // If the method returned a reference, then we can't release the original
  7795. // object yet, because the reference may be to a member of it
  7796. if( objType.isTemporary &&
  7797. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7798. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  7799. {
  7800. // Remember the object's variable, so that it can be released
  7801. // later on when the reference to its member goes out of scope
  7802. ctx->type.isTemporary = true;
  7803. ctx->type.stackOffset = objType.stackOffset;
  7804. }
  7805. else
  7806. {
  7807. // As the index operator didn't return a reference to a
  7808. // member we can release the original object now
  7809. ReleaseTemporaryVariable(objType, &ctx->bc);
  7810. }
  7811. // Found matching operator
  7812. return 1;
  7813. }
  7814. else if( ops.GetLength() > 1 )
  7815. {
  7816. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7817. PrintMatchingFuncs(ops, node);
  7818. ctx->type.SetDummy();
  7819. // Compiler error
  7820. return -1;
  7821. }
  7822. }
  7823. // No matching operator
  7824. return 0;
  7825. }
  7826. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  7827. {
  7828. if( objectType )
  7829. {
  7830. // The ASHANDLE type is really a value type, so if it is a
  7831. // local variable on the stack it must not be dereferenced
  7832. if( !(objectType->flags & asOBJ_ASHANDLE) ||
  7833. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  7834. Dereference(ctx, true);
  7835. // This following warning was removed as there may be valid reasons
  7836. // for calling non-const methods on temporary objects, and we shouldn't
  7837. // warn when there is no way of removing the warning.
  7838. /*
  7839. // Warn if the method is non-const and the object is temporary
  7840. // since the changes will be lost when the object is destroyed.
  7841. // If the object is accessed through a handle, then it is assumed
  7842. // the object is not temporary, even though the handle is.
  7843. if( ctx->type.isTemporary &&
  7844. !ctx->type.dataType.IsObjectHandle() &&
  7845. !engine->scriptFunctions[funcId]->isReadOnly )
  7846. {
  7847. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  7848. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  7849. }
  7850. */ }
  7851. asCByteCode objBC(engine);
  7852. objBC.AddCode(&ctx->bc);
  7853. PrepareFunctionCall(funcId, &ctx->bc, args);
  7854. // Verify if any of the args variable offsets are used in the other code.
  7855. // If they are exchange the offset for a new one
  7856. asUINT n;
  7857. for( n = 0; n < args.GetLength(); n++ )
  7858. {
  7859. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  7860. {
  7861. // Release the current temporary variable
  7862. ReleaseTemporaryVariable(args[n]->type, 0);
  7863. asCArray<int> usedVars;
  7864. objBC.GetVarsUsed(usedVars);
  7865. ctx->bc.GetVarsUsed(usedVars);
  7866. asCDataType dt = args[n]->type.dataType;
  7867. dt.MakeReference(false);
  7868. int newOffset = AllocateVariableNotIn(dt, true, &usedVars, IsVariableOnHeap(args[n]->type.stackOffset));
  7869. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  7870. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  7871. args[n]->type.stackOffset = (short)newOffset;
  7872. args[n]->type.isTemporary = true;
  7873. args[n]->type.isVariable = true;
  7874. }
  7875. }
  7876. #ifndef AS_OLD
  7877. // If the function will return a value type on the stack, then we must allocate space
  7878. // for that here and push the address on the stack as a hidden argument to the function
  7879. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  7880. if( func->DoesReturnOnStack() )
  7881. {
  7882. asASSERT(!useVariable);
  7883. useVariable = true;
  7884. stackOffset = AllocateVariable(func->returnType, true);
  7885. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  7886. }
  7887. #endif
  7888. ctx->bc.AddCode(&objBC);
  7889. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  7890. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  7891. }
  7892. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7893. {
  7894. IsVariableInitialized(&lctx->type, node);
  7895. IsVariableInitialized(&rctx->type, node);
  7896. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  7897. node->tokenType == ttIs || node->tokenType == ttNotIs )
  7898. {
  7899. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  7900. return 0;
  7901. }
  7902. else
  7903. {
  7904. // Compile an overloaded operator for the two operands
  7905. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  7906. return 0;
  7907. // If both operands are objects, then we shouldn't continue
  7908. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  7909. {
  7910. asCString str;
  7911. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  7912. Error(str.AddressOf(), node);
  7913. ctx->type.SetDummy();
  7914. return -1;
  7915. }
  7916. // Process the property get accessors (if any)
  7917. ProcessPropertyGetAccessor(lctx, node);
  7918. ProcessPropertyGetAccessor(rctx, node);
  7919. // Make sure we have two variables or constants
  7920. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  7921. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  7922. // Make sure lctx doesn't end up with a variable used in rctx
  7923. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  7924. {
  7925. asCArray<int> vars;
  7926. rctx->bc.GetVarsUsed(vars);
  7927. int offset = AllocateVariableNotIn(lctx->type.dataType, true, &vars);
  7928. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  7929. ReleaseTemporaryVariable(offset, 0);
  7930. }
  7931. // Math operators
  7932. // + - * / % += -= *= /= %=
  7933. int op = node->tokenType;
  7934. if( op == ttPlus || op == ttAddAssign ||
  7935. op == ttMinus || op == ttSubAssign ||
  7936. op == ttStar || op == ttMulAssign ||
  7937. op == ttSlash || op == ttDivAssign ||
  7938. op == ttPercent || op == ttModAssign )
  7939. {
  7940. CompileMathOperator(node, lctx, rctx, ctx);
  7941. return 0;
  7942. }
  7943. // Bitwise operators
  7944. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  7945. if( op == ttAmp || op == ttAndAssign ||
  7946. op == ttBitOr || op == ttOrAssign ||
  7947. op == ttBitXor || op == ttXorAssign ||
  7948. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  7949. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  7950. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  7951. {
  7952. CompileBitwiseOperator(node, lctx, rctx, ctx);
  7953. return 0;
  7954. }
  7955. // Comparison operators
  7956. // == != < > <= >=
  7957. if( op == ttEqual || op == ttNotEqual ||
  7958. op == ttLessThan || op == ttLessThanOrEqual ||
  7959. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  7960. {
  7961. CompileComparisonOperator(node, lctx, rctx, ctx);
  7962. return 0;
  7963. }
  7964. // Boolean operators
  7965. // && || ^^
  7966. if( op == ttAnd || op == ttOr || op == ttXor )
  7967. {
  7968. CompileBooleanOperator(node, lctx, rctx, ctx);
  7969. return 0;
  7970. }
  7971. }
  7972. asASSERT(false);
  7973. return -1;
  7974. }
  7975. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  7976. {
  7977. asCArray<int> excludeVars;
  7978. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  7979. ConvertToTempVariableNotIn(ctx, &excludeVars);
  7980. }
  7981. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  7982. {
  7983. // This is only used for primitive types and null handles
  7984. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  7985. ConvertToVariableNotIn(ctx, reservedVars);
  7986. if( !ctx->type.isTemporary )
  7987. {
  7988. if( ctx->type.dataType.IsPrimitive() )
  7989. {
  7990. // Copy the variable to a temporary variable
  7991. int offset = AllocateVariableNotIn(ctx->type.dataType, true, reservedVars);
  7992. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7993. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  7994. else
  7995. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  7996. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7997. }
  7998. else
  7999. {
  8000. // We should never get here
  8001. asASSERT(false);
  8002. }
  8003. }
  8004. }
  8005. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  8006. {
  8007. ConvertToTempVariableNotIn(ctx, (asCArray<int>*)0);
  8008. }
  8009. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  8010. {
  8011. ConvertToVariableNotIn(ctx, (asCArray<int>*)0);
  8012. }
  8013. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  8014. {
  8015. // We should never get here while the context is still an unprocessed property accessor
  8016. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  8017. asCArray<int> excludeVars;
  8018. if( reservedVars ) excludeVars.Concatenate(*reservedVars);
  8019. int offset;
  8020. if( !ctx->type.isVariable &&
  8021. (ctx->type.dataType.IsObjectHandle() ||
  8022. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  8023. {
  8024. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  8025. if( ctx->type.IsNullConstant() )
  8026. {
  8027. if( ctx->bc.GetLastInstr() == asBC_PshC4 || ctx->bc.GetLastInstr() == asBC_PshC8 )
  8028. ctx->bc.Pop(AS_PTR_SIZE); // Pop the null constant pushed onto the stack
  8029. #ifdef AS_64BIT_PTR
  8030. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, 0);
  8031. #else
  8032. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, 0);
  8033. #endif
  8034. }
  8035. else
  8036. {
  8037. // Copy the object handle to a variable
  8038. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  8039. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  8040. ctx->bc.Pop(AS_PTR_SIZE);
  8041. }
  8042. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8043. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8044. ctx->type.dataType.MakeHandle(true);
  8045. }
  8046. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  8047. ctx->type.dataType.IsPrimitive() )
  8048. {
  8049. if( ctx->type.isConstant )
  8050. {
  8051. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  8052. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8053. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  8054. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8055. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  8056. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8057. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  8058. else
  8059. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  8060. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8061. return;
  8062. }
  8063. else
  8064. {
  8065. asASSERT(ctx->type.dataType.IsPrimitive());
  8066. asASSERT(ctx->type.dataType.IsReference());
  8067. ctx->type.dataType.MakeReference(false);
  8068. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  8069. // Read the value from the address in the register directly into the variable
  8070. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8071. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  8072. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8073. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  8074. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8075. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  8076. else
  8077. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  8078. }
  8079. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8080. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8081. }
  8082. }
  8083. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  8084. {
  8085. asCArray<int> excludeVars;
  8086. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  8087. ConvertToVariableNotIn(ctx, &excludeVars);
  8088. }
  8089. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8090. {
  8091. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8092. // Implicitly convert the operands to a number type
  8093. asCDataType to;
  8094. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8095. to.SetTokenType(ttDouble);
  8096. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8097. to.SetTokenType(ttFloat);
  8098. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8099. {
  8100. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8101. to.SetTokenType(ttInt64);
  8102. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8103. to.SetTokenType(ttUInt64);
  8104. }
  8105. else
  8106. {
  8107. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8108. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8109. to.SetTokenType(ttInt);
  8110. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8111. to.SetTokenType(ttUInt);
  8112. }
  8113. // If doing an operation with double constant and float variable, the constant should be converted to float
  8114. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8115. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8116. to.SetTokenType(ttFloat);
  8117. // Do the actual conversion
  8118. asCArray<int> reservedVars;
  8119. rctx->bc.GetVarsUsed(reservedVars);
  8120. lctx->bc.GetVarsUsed(reservedVars);
  8121. if( lctx->type.dataType.IsReference() )
  8122. ConvertToVariableNotIn(lctx, &reservedVars);
  8123. if( rctx->type.dataType.IsReference() )
  8124. ConvertToVariableNotIn(rctx, &reservedVars);
  8125. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8126. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8127. // Verify that the conversion was successful
  8128. if( !lctx->type.dataType.IsIntegerType() &&
  8129. !lctx->type.dataType.IsUnsignedType() &&
  8130. !lctx->type.dataType.IsFloatType() &&
  8131. !lctx->type.dataType.IsDoubleType() )
  8132. {
  8133. asCString str;
  8134. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  8135. Error(str.AddressOf(), node);
  8136. ctx->type.SetDummy();
  8137. return;
  8138. }
  8139. if( !rctx->type.dataType.IsIntegerType() &&
  8140. !rctx->type.dataType.IsUnsignedType() &&
  8141. !rctx->type.dataType.IsFloatType() &&
  8142. !rctx->type.dataType.IsDoubleType() )
  8143. {
  8144. asCString str;
  8145. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  8146. Error(str.AddressOf(), node);
  8147. ctx->type.SetDummy();
  8148. return;
  8149. }
  8150. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8151. // Verify if we are dividing with a constant zero
  8152. int op = node->tokenType;
  8153. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  8154. (op == ttSlash || op == ttDivAssign ||
  8155. op == ttPercent || op == ttModAssign) )
  8156. {
  8157. Error(TXT_DIVIDE_BY_ZERO, node);
  8158. }
  8159. if( !isConstant )
  8160. {
  8161. ConvertToVariableNotIn(lctx, rctx);
  8162. ConvertToVariableNotIn(rctx, lctx);
  8163. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8164. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8165. if( op == ttAddAssign || op == ttSubAssign ||
  8166. op == ttMulAssign || op == ttDivAssign ||
  8167. op == ttModAssign )
  8168. {
  8169. // Merge the operands in the different order so that they are evaluated correctly
  8170. MergeExprBytecode(ctx, rctx);
  8171. MergeExprBytecode(ctx, lctx);
  8172. }
  8173. else
  8174. {
  8175. MergeExprBytecode(ctx, lctx);
  8176. MergeExprBytecode(ctx, rctx);
  8177. }
  8178. ProcessDeferredParams(ctx);
  8179. asEBCInstr instruction = asBC_ADDi;
  8180. if( lctx->type.dataType.IsIntegerType() ||
  8181. lctx->type.dataType.IsUnsignedType() )
  8182. {
  8183. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8184. {
  8185. if( op == ttPlus || op == ttAddAssign )
  8186. instruction = asBC_ADDi;
  8187. else if( op == ttMinus || op == ttSubAssign )
  8188. instruction = asBC_SUBi;
  8189. else if( op == ttStar || op == ttMulAssign )
  8190. instruction = asBC_MULi;
  8191. else if( op == ttSlash || op == ttDivAssign )
  8192. {
  8193. if( lctx->type.dataType.IsIntegerType() )
  8194. instruction = asBC_DIVi;
  8195. else
  8196. instruction = asBC_DIVu;
  8197. }
  8198. else if( op == ttPercent || op == ttModAssign )
  8199. {
  8200. if( lctx->type.dataType.IsIntegerType() )
  8201. instruction = asBC_MODi;
  8202. else
  8203. instruction = asBC_MODu;
  8204. }
  8205. }
  8206. else
  8207. {
  8208. if( op == ttPlus || op == ttAddAssign )
  8209. instruction = asBC_ADDi64;
  8210. else if( op == ttMinus || op == ttSubAssign )
  8211. instruction = asBC_SUBi64;
  8212. else if( op == ttStar || op == ttMulAssign )
  8213. instruction = asBC_MULi64;
  8214. else if( op == ttSlash || op == ttDivAssign )
  8215. {
  8216. if( lctx->type.dataType.IsIntegerType() )
  8217. instruction = asBC_DIVi64;
  8218. else
  8219. instruction = asBC_DIVu64;
  8220. }
  8221. else if( op == ttPercent || op == ttModAssign )
  8222. {
  8223. if( lctx->type.dataType.IsIntegerType() )
  8224. instruction = asBC_MODi64;
  8225. else
  8226. instruction = asBC_MODu64;
  8227. }
  8228. }
  8229. }
  8230. else if( lctx->type.dataType.IsFloatType() )
  8231. {
  8232. if( op == ttPlus || op == ttAddAssign )
  8233. instruction = asBC_ADDf;
  8234. else if( op == ttMinus || op == ttSubAssign )
  8235. instruction = asBC_SUBf;
  8236. else if( op == ttStar || op == ttMulAssign )
  8237. instruction = asBC_MULf;
  8238. else if( op == ttSlash || op == ttDivAssign )
  8239. instruction = asBC_DIVf;
  8240. else if( op == ttPercent || op == ttModAssign )
  8241. instruction = asBC_MODf;
  8242. }
  8243. else if( lctx->type.dataType.IsDoubleType() )
  8244. {
  8245. if( op == ttPlus || op == ttAddAssign )
  8246. instruction = asBC_ADDd;
  8247. else if( op == ttMinus || op == ttSubAssign )
  8248. instruction = asBC_SUBd;
  8249. else if( op == ttStar || op == ttMulAssign )
  8250. instruction = asBC_MULd;
  8251. else if( op == ttSlash || op == ttDivAssign )
  8252. instruction = asBC_DIVd;
  8253. else if( op == ttPercent || op == ttModAssign )
  8254. instruction = asBC_MODd;
  8255. }
  8256. else
  8257. {
  8258. // Shouldn't be possible
  8259. asASSERT(false);
  8260. }
  8261. // Do the operation
  8262. int a = AllocateVariable(lctx->type.dataType, true);
  8263. int b = lctx->type.stackOffset;
  8264. int c = rctx->type.stackOffset;
  8265. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8266. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8267. }
  8268. else
  8269. {
  8270. // Both values are constants
  8271. if( lctx->type.dataType.IsIntegerType() ||
  8272. lctx->type.dataType.IsUnsignedType() )
  8273. {
  8274. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8275. {
  8276. int v = 0;
  8277. if( op == ttPlus )
  8278. v = lctx->type.intValue + rctx->type.intValue;
  8279. else if( op == ttMinus )
  8280. v = lctx->type.intValue - rctx->type.intValue;
  8281. else if( op == ttStar )
  8282. v = lctx->type.intValue * rctx->type.intValue;
  8283. else if( op == ttSlash )
  8284. {
  8285. if( rctx->type.intValue == 0 )
  8286. v = 0;
  8287. else
  8288. if( lctx->type.dataType.IsIntegerType() )
  8289. v = lctx->type.intValue / rctx->type.intValue;
  8290. else
  8291. v = lctx->type.dwordValue / rctx->type.dwordValue;
  8292. }
  8293. else if( op == ttPercent )
  8294. {
  8295. if( rctx->type.intValue == 0 )
  8296. v = 0;
  8297. else
  8298. if( lctx->type.dataType.IsIntegerType() )
  8299. v = lctx->type.intValue % rctx->type.intValue;
  8300. else
  8301. v = lctx->type.dwordValue % rctx->type.dwordValue;
  8302. }
  8303. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8304. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8305. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  8306. ctx->type.dataType.SetTokenType(ttInt);
  8307. }
  8308. else
  8309. {
  8310. asQWORD v = 0;
  8311. if( op == ttPlus )
  8312. v = lctx->type.qwordValue + rctx->type.qwordValue;
  8313. else if( op == ttMinus )
  8314. v = lctx->type.qwordValue - rctx->type.qwordValue;
  8315. else if( op == ttStar )
  8316. v = lctx->type.qwordValue * rctx->type.qwordValue;
  8317. else if( op == ttSlash )
  8318. {
  8319. if( rctx->type.qwordValue == 0 )
  8320. v = 0;
  8321. else
  8322. if( lctx->type.dataType.IsIntegerType() )
  8323. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  8324. else
  8325. v = lctx->type.qwordValue / rctx->type.qwordValue;
  8326. }
  8327. else if( op == ttPercent )
  8328. {
  8329. if( rctx->type.qwordValue == 0 )
  8330. v = 0;
  8331. else
  8332. if( lctx->type.dataType.IsIntegerType() )
  8333. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  8334. else
  8335. v = lctx->type.qwordValue % rctx->type.qwordValue;
  8336. }
  8337. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8338. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8339. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  8340. ctx->type.dataType.SetTokenType(ttInt64);
  8341. }
  8342. }
  8343. else if( lctx->type.dataType.IsFloatType() )
  8344. {
  8345. float v = 0.0f;
  8346. if( op == ttPlus )
  8347. v = lctx->type.floatValue + rctx->type.floatValue;
  8348. else if( op == ttMinus )
  8349. v = lctx->type.floatValue - rctx->type.floatValue;
  8350. else if( op == ttStar )
  8351. v = lctx->type.floatValue * rctx->type.floatValue;
  8352. else if( op == ttSlash )
  8353. {
  8354. if( rctx->type.floatValue == 0 )
  8355. v = 0;
  8356. else
  8357. v = lctx->type.floatValue / rctx->type.floatValue;
  8358. }
  8359. else if( op == ttPercent )
  8360. {
  8361. if( rctx->type.floatValue == 0 )
  8362. v = 0;
  8363. else
  8364. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  8365. }
  8366. ctx->type.SetConstantF(lctx->type.dataType, v);
  8367. }
  8368. else if( lctx->type.dataType.IsDoubleType() )
  8369. {
  8370. double v = 0.0;
  8371. if( op == ttPlus )
  8372. v = lctx->type.doubleValue + rctx->type.doubleValue;
  8373. else if( op == ttMinus )
  8374. v = lctx->type.doubleValue - rctx->type.doubleValue;
  8375. else if( op == ttStar )
  8376. v = lctx->type.doubleValue * rctx->type.doubleValue;
  8377. else if( op == ttSlash )
  8378. {
  8379. if( rctx->type.doubleValue == 0 )
  8380. v = 0;
  8381. else
  8382. v = lctx->type.doubleValue / rctx->type.doubleValue;
  8383. }
  8384. else if( op == ttPercent )
  8385. {
  8386. if( rctx->type.doubleValue == 0 )
  8387. v = 0;
  8388. else
  8389. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  8390. }
  8391. ctx->type.SetConstantD(lctx->type.dataType, v);
  8392. }
  8393. else
  8394. {
  8395. // Shouldn't be possible
  8396. asASSERT(false);
  8397. }
  8398. }
  8399. }
  8400. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8401. {
  8402. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8403. int op = node->tokenType;
  8404. if( op == ttAmp || op == ttAndAssign ||
  8405. op == ttBitOr || op == ttOrAssign ||
  8406. op == ttBitXor || op == ttXorAssign )
  8407. {
  8408. // Convert left hand operand to integer if it's not already one
  8409. asCDataType to;
  8410. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  8411. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8412. to.SetTokenType(ttUInt64);
  8413. else
  8414. to.SetTokenType(ttUInt);
  8415. // Do the actual conversion
  8416. asCArray<int> reservedVars;
  8417. rctx->bc.GetVarsUsed(reservedVars);
  8418. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8419. // Verify that the conversion was successful
  8420. if( !lctx->type.dataType.IsUnsignedType() )
  8421. {
  8422. asCString str;
  8423. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8424. Error(str.AddressOf(), node);
  8425. }
  8426. // Convert right hand operand to same type as left hand operand
  8427. asCArray<int> vars;
  8428. lctx->bc.GetVarsUsed(vars);
  8429. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true, &vars);
  8430. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  8431. {
  8432. asCString str;
  8433. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  8434. Error(str.AddressOf(), node);
  8435. }
  8436. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8437. if( !isConstant )
  8438. {
  8439. ConvertToVariableNotIn(lctx, rctx);
  8440. ConvertToVariableNotIn(rctx, lctx);
  8441. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8442. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8443. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  8444. {
  8445. // Compound assignments execute the right hand value first
  8446. MergeExprBytecode(ctx, rctx);
  8447. MergeExprBytecode(ctx, lctx);
  8448. }
  8449. else
  8450. {
  8451. MergeExprBytecode(ctx, lctx);
  8452. MergeExprBytecode(ctx, rctx);
  8453. }
  8454. ProcessDeferredParams(ctx);
  8455. asEBCInstr instruction = asBC_BAND;
  8456. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8457. {
  8458. if( op == ttAmp || op == ttAndAssign )
  8459. instruction = asBC_BAND;
  8460. else if( op == ttBitOr || op == ttOrAssign )
  8461. instruction = asBC_BOR;
  8462. else if( op == ttBitXor || op == ttXorAssign )
  8463. instruction = asBC_BXOR;
  8464. }
  8465. else
  8466. {
  8467. if( op == ttAmp || op == ttAndAssign )
  8468. instruction = asBC_BAND64;
  8469. else if( op == ttBitOr || op == ttOrAssign )
  8470. instruction = asBC_BOR64;
  8471. else if( op == ttBitXor || op == ttXorAssign )
  8472. instruction = asBC_BXOR64;
  8473. }
  8474. // Do the operation
  8475. int a = AllocateVariable(lctx->type.dataType, true);
  8476. int b = lctx->type.stackOffset;
  8477. int c = rctx->type.stackOffset;
  8478. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8479. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8480. }
  8481. else
  8482. {
  8483. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8484. {
  8485. asQWORD v = 0;
  8486. if( op == ttAmp )
  8487. v = lctx->type.qwordValue & rctx->type.qwordValue;
  8488. else if( op == ttBitOr )
  8489. v = lctx->type.qwordValue | rctx->type.qwordValue;
  8490. else if( op == ttBitXor )
  8491. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  8492. // Remember the result
  8493. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8494. }
  8495. else
  8496. {
  8497. asDWORD v = 0;
  8498. if( op == ttAmp )
  8499. v = lctx->type.dwordValue & rctx->type.dwordValue;
  8500. else if( op == ttBitOr )
  8501. v = lctx->type.dwordValue | rctx->type.dwordValue;
  8502. else if( op == ttBitXor )
  8503. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  8504. // Remember the result
  8505. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8506. }
  8507. }
  8508. }
  8509. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8510. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8511. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8512. {
  8513. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  8514. if( lctx->type.dataType.IsObject() )
  8515. {
  8516. asCString str;
  8517. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  8518. Error(str.AddressOf(), node);
  8519. // Set an integer value and allow the compiler to continue
  8520. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  8521. return;
  8522. }
  8523. // Convert left hand operand to integer if it's not already one
  8524. asCDataType to = lctx->type.dataType;
  8525. if( lctx->type.dataType.IsUnsignedType() &&
  8526. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  8527. {
  8528. to = asCDataType::CreatePrimitive(ttUInt, false);
  8529. }
  8530. else if( !lctx->type.dataType.IsUnsignedType() )
  8531. {
  8532. asCDataType to;
  8533. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8534. to.SetTokenType(ttInt64);
  8535. else
  8536. to.SetTokenType(ttInt);
  8537. }
  8538. // Do the actual conversion
  8539. asCArray<int> reservedVars;
  8540. rctx->bc.GetVarsUsed(reservedVars);
  8541. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8542. // Verify that the conversion was successful
  8543. if( lctx->type.dataType != to )
  8544. {
  8545. asCString str;
  8546. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8547. Error(str.AddressOf(), node);
  8548. }
  8549. // Right operand must be 32bit uint
  8550. asCArray<int> vars;
  8551. lctx->bc.GetVarsUsed(vars);
  8552. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true, &vars);
  8553. if( !rctx->type.dataType.IsUnsignedType() )
  8554. {
  8555. asCString str;
  8556. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  8557. Error(str.AddressOf(), node);
  8558. }
  8559. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8560. if( !isConstant )
  8561. {
  8562. ConvertToVariableNotIn(lctx, rctx);
  8563. ConvertToVariableNotIn(rctx, lctx);
  8564. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8565. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8566. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  8567. {
  8568. // Compound assignments execute the right hand value first
  8569. MergeExprBytecode(ctx, rctx);
  8570. MergeExprBytecode(ctx, lctx);
  8571. }
  8572. else
  8573. {
  8574. MergeExprBytecode(ctx, lctx);
  8575. MergeExprBytecode(ctx, rctx);
  8576. }
  8577. ProcessDeferredParams(ctx);
  8578. asEBCInstr instruction = asBC_BSLL;
  8579. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8580. {
  8581. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8582. instruction = asBC_BSLL;
  8583. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8584. instruction = asBC_BSRL;
  8585. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8586. instruction = asBC_BSRA;
  8587. }
  8588. else
  8589. {
  8590. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8591. instruction = asBC_BSLL64;
  8592. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8593. instruction = asBC_BSRL64;
  8594. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8595. instruction = asBC_BSRA64;
  8596. }
  8597. // Do the operation
  8598. int a = AllocateVariable(lctx->type.dataType, true);
  8599. int b = lctx->type.stackOffset;
  8600. int c = rctx->type.stackOffset;
  8601. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8602. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8603. }
  8604. else
  8605. {
  8606. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8607. {
  8608. asDWORD v = 0;
  8609. if( op == ttBitShiftLeft )
  8610. v = lctx->type.dwordValue << rctx->type.dwordValue;
  8611. else if( op == ttBitShiftRight )
  8612. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  8613. else if( op == ttBitShiftRightArith )
  8614. v = lctx->type.intValue >> rctx->type.dwordValue;
  8615. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8616. }
  8617. else
  8618. {
  8619. asQWORD v = 0;
  8620. if( op == ttBitShiftLeft )
  8621. v = lctx->type.qwordValue << rctx->type.dwordValue;
  8622. else if( op == ttBitShiftRight )
  8623. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  8624. else if( op == ttBitShiftRightArith )
  8625. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  8626. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8627. }
  8628. }
  8629. }
  8630. }
  8631. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8632. {
  8633. // Both operands must be of the same type
  8634. // Implicitly convert the operands to a number type
  8635. asCDataType to;
  8636. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8637. to.SetTokenType(ttDouble);
  8638. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8639. to.SetTokenType(ttFloat);
  8640. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8641. {
  8642. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8643. to.SetTokenType(ttInt64);
  8644. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8645. to.SetTokenType(ttUInt64);
  8646. }
  8647. else
  8648. {
  8649. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8650. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8651. to.SetTokenType(ttInt);
  8652. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8653. to.SetTokenType(ttUInt);
  8654. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  8655. to.SetTokenType(ttBool);
  8656. }
  8657. // If doing an operation with double constant and float variable, the constant should be converted to float
  8658. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8659. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8660. to.SetTokenType(ttFloat);
  8661. // Is it an operation on signed values?
  8662. bool signMismatch = false;
  8663. if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
  8664. {
  8665. if( lctx->type.dataType.GetTokenType() == ttUInt64 )
  8666. {
  8667. if( !lctx->type.isConstant )
  8668. signMismatch = true;
  8669. else if( lctx->type.qwordValue & (I64(1)<<63) )
  8670. signMismatch = true;
  8671. }
  8672. if( lctx->type.dataType.GetTokenType() == ttUInt )
  8673. {
  8674. if( !lctx->type.isConstant )
  8675. signMismatch = true;
  8676. else if( lctx->type.dwordValue & (1<<31) )
  8677. signMismatch = true;
  8678. }
  8679. if( rctx->type.dataType.GetTokenType() == ttUInt64 )
  8680. {
  8681. if( !rctx->type.isConstant )
  8682. signMismatch = true;
  8683. else if( rctx->type.qwordValue & (I64(1)<<63) )
  8684. signMismatch = true;
  8685. }
  8686. if( rctx->type.dataType.GetTokenType() == ttUInt )
  8687. {
  8688. if( !rctx->type.isConstant )
  8689. signMismatch = true;
  8690. else if( rctx->type.dwordValue & (1<<31) )
  8691. signMismatch = true;
  8692. }
  8693. }
  8694. // Check for signed/unsigned mismatch
  8695. if( signMismatch )
  8696. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  8697. // Do the actual conversion
  8698. asCArray<int> reservedVars;
  8699. rctx->bc.GetVarsUsed(reservedVars);
  8700. if( lctx->type.dataType.IsReference() )
  8701. ConvertToVariableNotIn(lctx, &reservedVars);
  8702. if( rctx->type.dataType.IsReference() )
  8703. ConvertToVariableNotIn(rctx, &reservedVars);
  8704. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8705. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8706. // Verify that the conversion was successful
  8707. bool ok = true;
  8708. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8709. {
  8710. asCString str;
  8711. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8712. Error(str.AddressOf(), node);
  8713. ok = false;
  8714. }
  8715. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8716. {
  8717. asCString str;
  8718. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8719. Error(str.AddressOf(), node);
  8720. ok = false;
  8721. }
  8722. if( !ok )
  8723. {
  8724. // It wasn't possible to get two valid operands, so we just return
  8725. // a boolean result and let the compiler continue.
  8726. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8727. return;
  8728. }
  8729. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8730. int op = node->tokenType;
  8731. if( !isConstant )
  8732. {
  8733. if( to.IsBooleanType() )
  8734. {
  8735. int op = node->tokenType;
  8736. if( op == ttEqual || op == ttNotEqual )
  8737. {
  8738. // Must convert to temporary variable, because we are changing the value before comparison
  8739. ConvertToTempVariableNotIn(lctx, rctx);
  8740. ConvertToTempVariableNotIn(rctx, lctx);
  8741. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8742. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8743. // Make sure they are equal if not false
  8744. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8745. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8746. MergeExprBytecode(ctx, lctx);
  8747. MergeExprBytecode(ctx, rctx);
  8748. ProcessDeferredParams(ctx);
  8749. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8750. int b = lctx->type.stackOffset;
  8751. int c = rctx->type.stackOffset;
  8752. if( op == ttEqual )
  8753. {
  8754. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8755. ctx->bc.Instr(asBC_TZ);
  8756. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8757. }
  8758. else if( op == ttNotEqual )
  8759. {
  8760. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8761. ctx->bc.Instr(asBC_TNZ);
  8762. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8763. }
  8764. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8765. }
  8766. else
  8767. {
  8768. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8769. Error(TXT_ILLEGAL_OPERATION, node);
  8770. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  8771. }
  8772. }
  8773. else
  8774. {
  8775. ConvertToVariableNotIn(lctx, rctx);
  8776. ConvertToVariableNotIn(rctx, lctx);
  8777. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8778. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8779. MergeExprBytecode(ctx, lctx);
  8780. MergeExprBytecode(ctx, rctx);
  8781. ProcessDeferredParams(ctx);
  8782. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  8783. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8784. iCmp = asBC_CMPi;
  8785. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8786. iCmp = asBC_CMPu;
  8787. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8788. iCmp = asBC_CMPi64;
  8789. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8790. iCmp = asBC_CMPu64;
  8791. else if( lctx->type.dataType.IsFloatType() )
  8792. iCmp = asBC_CMPf;
  8793. else if( lctx->type.dataType.IsDoubleType() )
  8794. iCmp = asBC_CMPd;
  8795. else
  8796. asASSERT(false);
  8797. if( op == ttEqual )
  8798. iT = asBC_TZ;
  8799. else if( op == ttNotEqual )
  8800. iT = asBC_TNZ;
  8801. else if( op == ttLessThan )
  8802. iT = asBC_TS;
  8803. else if( op == ttLessThanOrEqual )
  8804. iT = asBC_TNP;
  8805. else if( op == ttGreaterThan )
  8806. iT = asBC_TP;
  8807. else if( op == ttGreaterThanOrEqual )
  8808. iT = asBC_TNS;
  8809. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8810. int b = lctx->type.stackOffset;
  8811. int c = rctx->type.stackOffset;
  8812. ctx->bc.InstrW_W(iCmp, b, c);
  8813. ctx->bc.Instr(iT);
  8814. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8815. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8816. }
  8817. }
  8818. else
  8819. {
  8820. if( to.IsBooleanType() )
  8821. {
  8822. int op = node->tokenType;
  8823. if( op == ttEqual || op == ttNotEqual )
  8824. {
  8825. // Make sure they are equal if not false
  8826. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8827. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8828. asDWORD v = 0;
  8829. if( op == ttEqual )
  8830. {
  8831. v = lctx->type.intValue - rctx->type.intValue;
  8832. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8833. }
  8834. else if( op == ttNotEqual )
  8835. {
  8836. v = lctx->type.intValue - rctx->type.intValue;
  8837. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8838. }
  8839. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  8840. }
  8841. else
  8842. {
  8843. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8844. Error(TXT_ILLEGAL_OPERATION, node);
  8845. }
  8846. }
  8847. else
  8848. {
  8849. int i = 0;
  8850. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8851. {
  8852. int v = lctx->type.intValue - rctx->type.intValue;
  8853. if( v < 0 ) i = -1;
  8854. if( v > 0 ) i = 1;
  8855. }
  8856. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8857. {
  8858. asDWORD v1 = lctx->type.dwordValue;
  8859. asDWORD v2 = rctx->type.dwordValue;
  8860. if( v1 < v2 ) i = -1;
  8861. if( v1 > v2 ) i = 1;
  8862. }
  8863. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8864. {
  8865. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  8866. if( v < 0 ) i = -1;
  8867. if( v > 0 ) i = 1;
  8868. }
  8869. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8870. {
  8871. asQWORD v1 = lctx->type.qwordValue;
  8872. asQWORD v2 = rctx->type.qwordValue;
  8873. if( v1 < v2 ) i = -1;
  8874. if( v1 > v2 ) i = 1;
  8875. }
  8876. else if( lctx->type.dataType.IsFloatType() )
  8877. {
  8878. float v = lctx->type.floatValue - rctx->type.floatValue;
  8879. if( v < 0 ) i = -1;
  8880. if( v > 0 ) i = 1;
  8881. }
  8882. else if( lctx->type.dataType.IsDoubleType() )
  8883. {
  8884. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  8885. if( v < 0 ) i = -1;
  8886. if( v > 0 ) i = 1;
  8887. }
  8888. if( op == ttEqual )
  8889. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8890. else if( op == ttNotEqual )
  8891. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8892. else if( op == ttLessThan )
  8893. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8894. else if( op == ttLessThanOrEqual )
  8895. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8896. else if( op == ttGreaterThan )
  8897. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8898. else if( op == ttGreaterThanOrEqual )
  8899. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8900. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  8901. }
  8902. }
  8903. }
  8904. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  8905. {
  8906. // Put the result on the stack
  8907. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  8908. if( asReference )
  8909. ctx->type.dataType.MakeReference(true);
  8910. else
  8911. {
  8912. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8913. ctx->bc.Instr(asBC_RDS4);
  8914. else
  8915. ctx->bc.Instr(asBC_RDS8);
  8916. }
  8917. }
  8918. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8919. {
  8920. // Both operands must be booleans
  8921. asCDataType to;
  8922. to.SetTokenType(ttBool);
  8923. // Do the actual conversion
  8924. asCArray<int> reservedVars;
  8925. rctx->bc.GetVarsUsed(reservedVars);
  8926. lctx->bc.GetVarsUsed(reservedVars);
  8927. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8928. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8929. // Verify that the conversion was successful
  8930. if( !lctx->type.dataType.IsBooleanType() )
  8931. {
  8932. asCString str;
  8933. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  8934. Error(str.AddressOf(), node);
  8935. // Force the conversion to allow compilation to proceed
  8936. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8937. }
  8938. if( !rctx->type.dataType.IsBooleanType() )
  8939. {
  8940. asCString str;
  8941. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  8942. Error(str.AddressOf(), node);
  8943. // Force the conversion to allow compilation to proceed
  8944. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8945. }
  8946. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8947. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  8948. // What kind of operator is it?
  8949. int op = node->tokenType;
  8950. if( op == ttXor )
  8951. {
  8952. if( !isConstant )
  8953. {
  8954. // Must convert to temporary variable, because we are changing the value before comparison
  8955. ConvertToTempVariableNotIn(lctx, rctx);
  8956. ConvertToTempVariableNotIn(rctx, lctx);
  8957. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8958. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8959. // Make sure they are equal if not false
  8960. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8961. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8962. MergeExprBytecode(ctx, lctx);
  8963. MergeExprBytecode(ctx, rctx);
  8964. ProcessDeferredParams(ctx);
  8965. int a = AllocateVariable(ctx->type.dataType, true);
  8966. int b = lctx->type.stackOffset;
  8967. int c = rctx->type.stackOffset;
  8968. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  8969. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8970. }
  8971. else
  8972. {
  8973. // Make sure they are equal if not false
  8974. #if AS_SIZEOF_BOOL == 1
  8975. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8976. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8977. asBYTE v = 0;
  8978. v = lctx->type.byteValue - rctx->type.byteValue;
  8979. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8980. ctx->type.isConstant = true;
  8981. ctx->type.byteValue = v;
  8982. #else
  8983. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8984. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8985. asDWORD v = 0;
  8986. v = lctx->type.intValue - rctx->type.intValue;
  8987. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8988. ctx->type.isConstant = true;
  8989. ctx->type.dwordValue = v;
  8990. #endif
  8991. }
  8992. }
  8993. else if( op == ttAnd ||
  8994. op == ttOr )
  8995. {
  8996. if( !isConstant )
  8997. {
  8998. // If or-operator and first value is 1 the second value shouldn't be calculated
  8999. // if and-operator and first value is 0 the second value shouldn't be calculated
  9000. ConvertToVariable(lctx);
  9001. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9002. MergeExprBytecode(ctx, lctx);
  9003. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  9004. int label1 = nextLabel++;
  9005. int label2 = nextLabel++;
  9006. if( op == ttAnd )
  9007. {
  9008. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9009. ctx->bc.Instr(asBC_ClrHi);
  9010. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  9011. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  9012. ctx->bc.InstrINT(asBC_JMP, label2);
  9013. }
  9014. else if( op == ttOr )
  9015. {
  9016. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9017. ctx->bc.Instr(asBC_ClrHi);
  9018. ctx->bc.InstrDWORD(asBC_JZ, label1);
  9019. #if AS_SIZEOF_BOOL == 1
  9020. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9021. #else
  9022. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9023. #endif
  9024. ctx->bc.InstrINT(asBC_JMP, label2);
  9025. }
  9026. ctx->bc.Label((short)label1);
  9027. ConvertToVariable(rctx);
  9028. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9029. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  9030. MergeExprBytecode(ctx, rctx);
  9031. ctx->bc.Label((short)label2);
  9032. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  9033. }
  9034. else
  9035. {
  9036. #if AS_SIZEOF_BOOL == 1
  9037. asBYTE v = 0;
  9038. if( op == ttAnd )
  9039. v = lctx->type.byteValue && rctx->type.byteValue;
  9040. else if( op == ttOr )
  9041. v = lctx->type.byteValue || rctx->type.byteValue;
  9042. // Remember the result
  9043. ctx->type.isConstant = true;
  9044. ctx->type.byteValue = v;
  9045. #else
  9046. asDWORD v = 0;
  9047. if( op == ttAnd )
  9048. v = lctx->type.dwordValue && rctx->type.dwordValue;
  9049. else if( op == ttOr )
  9050. v = lctx->type.dwordValue || rctx->type.dwordValue;
  9051. // Remember the result
  9052. ctx->type.isConstant = true;
  9053. ctx->type.dwordValue = v;
  9054. #endif
  9055. }
  9056. }
  9057. }
  9058. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9059. {
  9060. // Process the property accessor as get
  9061. ProcessPropertyGetAccessor(lctx, node);
  9062. ProcessPropertyGetAccessor(rctx, node);
  9063. // Make sure lctx doesn't end up with a variable used in rctx
  9064. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9065. {
  9066. asCArray<int> vars;
  9067. rctx->bc.GetVarsUsed(vars);
  9068. int offset = AllocateVariable(lctx->type.dataType, true);
  9069. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9070. ReleaseTemporaryVariable(offset, 0);
  9071. }
  9072. // Warn if not both operands are explicit handles
  9073. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  9074. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  9075. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  9076. {
  9077. Warning(TXT_HANDLE_COMPARISON, node);
  9078. }
  9079. // If one of the operands is a value type used as handle, we should look for the opEquals method
  9080. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  9081. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  9082. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  9083. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  9084. {
  9085. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9086. // Find the matching opEquals method
  9087. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9088. if( r == 0 )
  9089. {
  9090. // Try again by switching the order of the operands
  9091. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9092. }
  9093. if( r == 1 )
  9094. {
  9095. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  9096. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9097. // Success, don't continue
  9098. return;
  9099. }
  9100. else if( r == 0 )
  9101. {
  9102. // Couldn't find opEquals method
  9103. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  9104. }
  9105. // Compiler error, don't continue
  9106. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9107. return;
  9108. }
  9109. // Implicitly convert null to the other type
  9110. asCDataType to;
  9111. if( lctx->type.IsNullConstant() )
  9112. to = rctx->type.dataType;
  9113. else if( rctx->type.IsNullConstant() )
  9114. to = lctx->type.dataType;
  9115. else
  9116. {
  9117. // TODO: Use the common base type
  9118. to = lctx->type.dataType;
  9119. }
  9120. // Need to pop the value if it is a null constant
  9121. if( lctx->type.IsNullConstant() )
  9122. lctx->bc.Pop(AS_PTR_SIZE);
  9123. if( rctx->type.IsNullConstant() )
  9124. rctx->bc.Pop(AS_PTR_SIZE);
  9125. // Convert both sides to explicit handles
  9126. to.MakeHandle(true);
  9127. to.MakeReference(false);
  9128. // Do the conversion
  9129. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9130. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9131. // Both operands must be of the same type
  9132. // Verify that the conversion was successful
  9133. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  9134. {
  9135. asCString str;
  9136. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9137. Error(str.AddressOf(), node);
  9138. }
  9139. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  9140. {
  9141. asCString str;
  9142. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9143. Error(str.AddressOf(), node);
  9144. }
  9145. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  9146. int op = node->tokenType;
  9147. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  9148. {
  9149. // If the object handle already is in a variable we must manually pop it from the stack
  9150. if( lctx->type.isVariable )
  9151. lctx->bc.Pop(AS_PTR_SIZE);
  9152. if( rctx->type.isVariable )
  9153. rctx->bc.Pop(AS_PTR_SIZE);
  9154. // TODO: optimize: Treat the object handles as two integers, i.e. don't do REFCPY
  9155. ConvertToVariableNotIn(lctx, rctx);
  9156. ConvertToVariable(rctx);
  9157. MergeExprBytecode(ctx, lctx);
  9158. MergeExprBytecode(ctx, rctx);
  9159. int a = AllocateVariable(ctx->type.dataType, true);
  9160. int b = lctx->type.stackOffset;
  9161. int c = rctx->type.stackOffset;
  9162. // TODO: When saving the bytecode we must be able to determine that this is
  9163. // a comparison with a pointer, so that the instruction can be adapted
  9164. // to the pointer size on the platform that will execute it.
  9165. #ifdef AS_64BIT_PTR
  9166. ctx->bc.InstrW_W(asBC_CMPi64, b, c);
  9167. #else
  9168. ctx->bc.InstrW_W(asBC_CMPi, b, c);
  9169. #endif
  9170. if( op == ttEqual || op == ttIs )
  9171. ctx->bc.Instr(asBC_TZ);
  9172. else if( op == ttNotEqual || op == ttNotIs )
  9173. ctx->bc.Instr(asBC_TNZ);
  9174. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9175. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9176. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  9177. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  9178. ProcessDeferredParams(ctx);
  9179. }
  9180. else
  9181. {
  9182. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9183. Error(TXT_ILLEGAL_OPERATION, node);
  9184. }
  9185. }
  9186. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  9187. {
  9188. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  9189. // A shared object may not call non-shared functions
  9190. if( outFunc->objectType && outFunc->objectType->IsShared() )
  9191. {
  9192. if( descr->funcType == asFUNC_SCRIPT &&
  9193. (descr->objectType == 0 || !descr->objectType->IsShared()) )
  9194. {
  9195. asCString msg;
  9196. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  9197. Error(msg.AddressOf(), ctx->exprNode);
  9198. }
  9199. }
  9200. // Check if the function is private
  9201. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  9202. {
  9203. asCString msg;
  9204. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  9205. Error(msg.AddressOf(), ctx->exprNode);
  9206. }
  9207. int argSize = descr->GetSpaceNeededForArguments();
  9208. if( descr->objectType && descr->returnType.IsReference() &&
  9209. !ctx->type.isVariable && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  9210. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  9211. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  9212. {
  9213. // The class method we're calling is returning a reference, which may be to a member of the object.
  9214. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  9215. // TODO: optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  9216. int tempRef = AllocateVariable(ctx->type.dataType, true);
  9217. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  9218. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9219. // Add the release of this reference, as a deferred expression
  9220. asSDeferredParam deferred;
  9221. deferred.origExpr = 0;
  9222. deferred.argInOutFlags = asTM_INREF;
  9223. deferred.argNode = 0;
  9224. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  9225. ctx->deferredParams.PushLast(deferred);
  9226. }
  9227. ctx->type.Set(descr->returnType);
  9228. if( isConstructor )
  9229. {
  9230. // Sometimes the value types are allocated on the heap,
  9231. // which is when this way of constructing them is used.
  9232. asASSERT(useVariable == false);
  9233. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  9234. // The instruction has already moved the returned object to the variable
  9235. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  9236. ctx->type.isLValue = false;
  9237. // Clean up arguments
  9238. if( args )
  9239. AfterFunctionCall(funcId, *args, ctx, false);
  9240. ProcessDeferredParams(ctx);
  9241. return;
  9242. }
  9243. else
  9244. {
  9245. if( descr->objectType )
  9246. argSize += AS_PTR_SIZE;
  9247. #ifndef AS_OLD
  9248. // If the function returns an object by value the address of the location
  9249. // where the value should be stored is passed as an argument too
  9250. if( descr->DoesReturnOnStack() )
  9251. {
  9252. argSize += AS_PTR_SIZE;
  9253. }
  9254. #endif
  9255. if( descr->funcType == asFUNC_IMPORTED )
  9256. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  9257. // TODO: Maybe we need two different byte codes
  9258. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  9259. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  9260. else if( descr->funcType == asFUNC_SCRIPT )
  9261. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  9262. else if( descr->funcType == asFUNC_SYSTEM )
  9263. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  9264. else if( descr->funcType == asFUNC_FUNCDEF )
  9265. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  9266. }
  9267. if( ctx->type.dataType.IsObject() && !descr->returnType.IsReference() )
  9268. {
  9269. int returnOffset = 0;
  9270. #ifndef AS_OLD
  9271. if( descr->DoesReturnOnStack() )
  9272. {
  9273. asASSERT( useVariable );
  9274. // The variable was allocated before the function was called
  9275. returnOffset = varOffset;
  9276. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9277. // The variable was initialized by the function, so we need to mark it as initialized here
  9278. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  9279. }
  9280. else
  9281. #endif
  9282. {
  9283. if( useVariable )
  9284. {
  9285. // Use the given variable
  9286. returnOffset = varOffset;
  9287. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  9288. }
  9289. else
  9290. {
  9291. // Allocate a temporary variable for the returned object
  9292. // The returned object will actually be allocated on the heap, so
  9293. // we must force the allocation of the variable to do the same
  9294. returnOffset = AllocateVariable(descr->returnType, true, true);
  9295. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9296. }
  9297. // Move the pointer from the object register to the temporary variable
  9298. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9299. }
  9300. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  9301. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  9302. // Clean up arguments
  9303. if( args )
  9304. AfterFunctionCall(funcId, *args, ctx, false);
  9305. ProcessDeferredParams(ctx);
  9306. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9307. }
  9308. else if( descr->returnType.IsReference() )
  9309. {
  9310. asASSERT(useVariable == false);
  9311. // We cannot clean up the arguments yet, because the
  9312. // reference might be pointing to one of them.
  9313. // Clean up arguments
  9314. if( args )
  9315. AfterFunctionCall(funcId, *args, ctx, true);
  9316. // Do not process the output parameters yet, because it
  9317. // might invalidate the returned reference
  9318. if( descr->returnType.IsPrimitive() )
  9319. ctx->type.Set(descr->returnType);
  9320. else
  9321. {
  9322. ctx->bc.Instr(asBC_PshRPtr);
  9323. if( descr->returnType.IsObject() &&
  9324. (!descr->returnType.IsObjectHandle() || (descr->returnType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  9325. {
  9326. // We are getting the pointer to the object
  9327. // not a pointer to a object variable
  9328. ctx->type.dataType.MakeReference(false);
  9329. }
  9330. }
  9331. // A returned reference can be used as lvalue
  9332. ctx->type.isLValue = true;
  9333. }
  9334. else
  9335. {
  9336. asASSERT(useVariable == false);
  9337. if( descr->returnType.GetSizeInMemoryBytes() )
  9338. {
  9339. // Allocate a temporary variable to hold the value, but make sure
  9340. // the temporary variable isn't used in any of the deferred arguments
  9341. asCArray<int> vars;
  9342. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  9343. {
  9344. asSExprContext *expr = (*args)[n]->origExpr;
  9345. if( expr )
  9346. expr->bc.GetVarsUsed(vars);
  9347. }
  9348. int offset = AllocateVariableNotIn(descr->returnType, true, &vars);
  9349. ctx->type.SetVariable(descr->returnType, offset, true);
  9350. // Move the value from the return register to the variable
  9351. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  9352. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  9353. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  9354. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  9355. }
  9356. else
  9357. ctx->type.Set(descr->returnType);
  9358. ctx->type.isLValue = false;
  9359. // Clean up arguments
  9360. if( args )
  9361. AfterFunctionCall(funcId, *args, ctx, false);
  9362. ProcessDeferredParams(ctx);
  9363. }
  9364. }
  9365. // This only merges the bytecode, but doesn't modify the type of the final context
  9366. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  9367. {
  9368. before->bc.AddCode(&after->bc);
  9369. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  9370. {
  9371. before->deferredParams.PushLast(after->deferredParams[n]);
  9372. after->deferredParams[n].origExpr = 0;
  9373. }
  9374. after->deferredParams.SetLength(0);
  9375. }
  9376. // This merges both bytecode and the type of the final context
  9377. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  9378. {
  9379. MergeExprBytecode(before, after);
  9380. before->type = after->type;
  9381. before->property_get = after->property_get;
  9382. before->property_set = after->property_set;
  9383. before->property_const = after->property_const;
  9384. before->property_handle = after->property_handle;
  9385. before->property_ref = after->property_ref;
  9386. before->property_arg = after->property_arg;
  9387. before->exprNode = after->exprNode;
  9388. after->property_arg = 0;
  9389. // Do not copy the origExpr member
  9390. }
  9391. void asCCompiler::FilterConst(asCArray<int> &funcs)
  9392. {
  9393. if( funcs.GetLength() == 0 ) return;
  9394. // This is only done for object methods
  9395. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  9396. if( desc->objectType == 0 ) return;
  9397. // Check if there are any non-const matches
  9398. asUINT n;
  9399. bool foundNonConst = false;
  9400. for( n = 0; n < funcs.GetLength(); n++ )
  9401. {
  9402. desc = builder->GetFunctionDescription(funcs[n]);
  9403. if( !desc->isReadOnly )
  9404. {
  9405. foundNonConst = true;
  9406. break;
  9407. }
  9408. }
  9409. if( foundNonConst )
  9410. {
  9411. // Remove all const methods
  9412. for( n = 0; n < funcs.GetLength(); n++ )
  9413. {
  9414. desc = builder->GetFunctionDescription(funcs[n]);
  9415. if( desc->isReadOnly )
  9416. {
  9417. if( n == funcs.GetLength() - 1 )
  9418. funcs.PopLast();
  9419. else
  9420. funcs[n] = funcs.PopLast();
  9421. n--;
  9422. }
  9423. }
  9424. }
  9425. }
  9426. END_AS_NAMESPACE