2
0

as_compiler.cpp 402 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2013 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Oorni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. BEGIN_AS_NAMESPACE
  40. //
  41. // The calling convention rules for script functions:
  42. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  43. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  44. // - The object pointer is always passed as the first argument, position 0
  45. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  46. //
  47. // TODO: I must correct the interpretation of a references to objects in the compiler.
  48. // A reference should mean that a pointer to the object is on the stack.
  49. // No expression should end up as non-references to objects, as the actual object is
  50. // never put on the stack.
  51. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  52. // Function parameters of called functions can also be non-references, but in that case it means the
  53. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  54. //
  55. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  56. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  57. // is currently stored, i.e. in variable, in register, on stack, etc.
  58. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  59. {
  60. builder = 0;
  61. script = 0;
  62. variables = 0;
  63. isProcessingDeferredParams = false;
  64. isCompilingDefaultArg = false;
  65. noCodeOutput = 0;
  66. }
  67. asCCompiler::~asCCompiler()
  68. {
  69. while( variables )
  70. {
  71. asCVariableScope *var = variables;
  72. variables = variables->parent;
  73. asDELETE(var,asCVariableScope);
  74. }
  75. }
  76. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  77. {
  78. this->builder = builder;
  79. this->engine = builder->engine;
  80. this->script = script;
  81. this->outFunc = outFunc;
  82. hasCompileErrors = false;
  83. m_isConstructor = false;
  84. m_isConstructorCalled = false;
  85. m_classDecl = 0;
  86. nextLabel = 0;
  87. breakLabels.SetLength(0);
  88. continueLabels.SetLength(0);
  89. byteCode.ClearAll();
  90. }
  91. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  92. {
  93. Reset(builder, script, outFunc);
  94. m_classDecl = classDecl;
  95. // Insert a JitEntry at the start of the function for JIT compilers
  96. byteCode.InstrPTR(asBC_JitEntry, 0);
  97. // Add a variable scope that might be needed to declare dummy variables
  98. // in case the member initialization refers to undefined symbols.
  99. AddVariableScope();
  100. // Initialize the class members that have no explicit expression first. This will allow the
  101. // base class' constructor to access these members without worry they will be uninitialized.
  102. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  103. CompileMemberInitialization(&byteCode, true);
  104. // If the class is derived from another, then the base class' default constructor must be called
  105. if( outFunc->objectType->derivedFrom )
  106. {
  107. // Make sure the base class really has a default constructor
  108. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  109. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node);
  110. // Call the base class' default constructor
  111. byteCode.InstrSHORT(asBC_PSF, 0);
  112. byteCode.Instr(asBC_RDSPtr);
  113. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  114. }
  115. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  116. // to access the base class members without worry they will be uninitialized
  117. CompileMemberInitialization(&byteCode, false);
  118. byteCode.OptimizeLocally(tempVariableOffsets);
  119. // If there are compile errors, there is no reason to build the final code
  120. if( hasCompileErrors )
  121. return -1;
  122. // Pop the object pointer from the stack
  123. byteCode.Ret(AS_PTR_SIZE);
  124. // Count total variable size
  125. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  126. outFunc->scriptData->variableSpace = varSize;
  127. FinalizeFunction();
  128. #ifdef AS_DEBUG
  129. // DEBUG: output byte code
  130. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc);
  131. #endif
  132. return 0;
  133. }
  134. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  135. {
  136. Reset(builder, script, outFunc);
  137. // Insert a JitEntry at the start of the function for JIT compilers
  138. byteCode.InstrPTR(asBC_JitEntry, 0);
  139. // Find the corresponding constructor
  140. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  141. int constructor = 0;
  142. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  143. {
  144. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  145. {
  146. constructor = dt.GetBehaviour()->constructors[n];
  147. break;
  148. }
  149. }
  150. // Allocate the class and instanciate it with the constructor
  151. int varOffset = AllocateVariable(dt, true);
  152. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  153. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  154. // Copy all arguments to the top of the stack
  155. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  156. int offset = (int)outFunc->GetSpaceNeededForArguments();
  157. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  158. {
  159. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  160. outFunc->parameterTypes[a].IsReference() )
  161. {
  162. offset -= AS_PTR_SIZE;
  163. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  164. }
  165. else
  166. {
  167. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  168. {
  169. offset -= 2;
  170. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  171. }
  172. else
  173. {
  174. offset -= 1;
  175. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  176. }
  177. }
  178. }
  179. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  180. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  181. // Return a handle to the newly created object
  182. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  183. byteCode.Ret(argDwords);
  184. FinalizeFunction();
  185. // Tell the virtual machine not to clean up parameters on exception
  186. outFunc->dontCleanUpOnException = true;
  187. /*
  188. #ifdef AS_DEBUG
  189. // DEBUG: output byte code
  190. asCString args;
  191. args.Format("%d", outFunc->parameterTypes.GetLength());
  192. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  193. #endif
  194. */
  195. return 0;
  196. }
  197. void asCCompiler::FinalizeFunction()
  198. {
  199. TimeIt("asCCompiler::FinalizeFunction");
  200. asASSERT( outFunc->scriptData );
  201. asUINT n;
  202. // Finalize the bytecode
  203. byteCode.Finalize(tempVariableOffsets);
  204. byteCode.ExtractObjectVariableInfo(outFunc);
  205. // Compile the list of object variables for the exception handler
  206. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  207. for( n = 0; n < variableAllocations.GetLength(); n++ )
  208. {
  209. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  210. {
  211. if( variableIsOnHeap[n] )
  212. {
  213. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  214. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  215. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  216. }
  217. }
  218. }
  219. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  220. for( n = 0; n < variableAllocations.GetLength(); n++ )
  221. {
  222. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  223. {
  224. if( !variableIsOnHeap[n] )
  225. {
  226. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  227. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  228. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  229. }
  230. }
  231. }
  232. // Copy byte code to the function
  233. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  234. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  235. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  236. outFunc->AddReferences();
  237. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  238. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  239. // Extract the script section indexes too if there are any entries that are different from the function's script section
  240. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  241. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  242. {
  243. if( byteCode.sectionIdxs[n] != lastIdx )
  244. {
  245. lastIdx = byteCode.sectionIdxs[n];
  246. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  247. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  248. }
  249. }
  250. }
  251. // internal
  252. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  253. {
  254. int stackPos = 0;
  255. if( outFunc->objectType )
  256. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  257. // Add the first variable scope, which the parameters and
  258. // variables declared in the outermost statement block is
  259. // part of.
  260. AddVariableScope();
  261. bool isDestructor = false;
  262. asCDataType returnType;
  263. // Examine return type
  264. returnType = outFunc->returnType;
  265. // Check if this is a constructor or destructor
  266. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  267. {
  268. if( outFunc->name[0] == '~' )
  269. isDestructor = true;
  270. else if( outFunc->objectType->name == outFunc->name )
  271. m_isConstructor = true;
  272. }
  273. // Is the return type allowed?
  274. if( (!returnType.CanBeInstanciated() && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  275. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  276. {
  277. // TODO: Hasn't this been validated by the builder already?
  278. asCString str;
  279. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  280. Error(str, func);
  281. }
  282. // If the return type is a value type returned by value the address of the
  283. // location where the value will be stored is pushed on the stack before
  284. // the arguments
  285. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  286. stackPos -= AS_PTR_SIZE;
  287. asCVariableScope vs(0);
  288. // Declare parameters
  289. asUINT n;
  290. for( n = 0; n < parameterNames.GetLength(); n++ )
  291. {
  292. // Get the parameter type
  293. asCDataType &type = outFunc->parameterTypes[n];
  294. asETypeModifiers inoutFlag = outFunc->inOutFlags[n];
  295. // Is the data type allowed?
  296. // TODO: Hasn't this been validated by the builder already?
  297. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  298. (!type.IsReference() && !type.CanBeInstanciated()) )
  299. {
  300. asCString parm = type.Format();
  301. if( inoutFlag == asTM_INREF )
  302. parm += "in";
  303. else if( inoutFlag == asTM_OUTREF )
  304. parm += "out";
  305. asCString str;
  306. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  307. Error(str, func);
  308. }
  309. // If the parameter has a name then declare it as variable
  310. if( parameterNames[n] != "" )
  311. {
  312. asCString &name = parameterNames[n];
  313. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  314. {
  315. // TODO: It might be an out-of-memory too
  316. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  317. }
  318. // Add marker for variable declaration
  319. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  320. outFunc->AddVariable(name, type, stackPos);
  321. }
  322. else
  323. vs.DeclareVariable("", type, stackPos, true);
  324. // Move to next parameter
  325. stackPos -= type.GetSizeOnStackDWords();
  326. }
  327. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  328. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  329. variables->DeclareVariable("return", returnType, stackPos, true);
  330. return stackPos;
  331. }
  332. void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
  333. {
  334. asASSERT( m_classDecl );
  335. // Initialize each member in the order they were declared
  336. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  337. {
  338. asCObjectProperty *prop = outFunc->objectType->properties[n];
  339. // Check if the property has an initialization expression
  340. asCScriptNode *declNode = 0;
  341. asCScriptNode *initNode = 0;
  342. asCScriptCode *initScript = 0;
  343. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  344. {
  345. if( m_classDecl->propInits[m].name == prop->name )
  346. {
  347. declNode = m_classDecl->propInits[m].declNode;
  348. initNode = m_classDecl->propInits[m].initNode;
  349. initScript = m_classDecl->propInits[m].file;
  350. break;
  351. }
  352. }
  353. // If declNode is null, the property was inherited in which case
  354. // it was already initialized by the base class' constructor
  355. if( declNode )
  356. {
  357. if( initNode )
  358. {
  359. if( onlyDefaults )
  360. continue;
  361. #ifdef AS_NO_MEMBER_INIT
  362. // Give an error as the initialization in the declaration has been disabled
  363. asCScriptCode *origScript = script;
  364. script = initScript;
  365. Error("Initialization of members in declaration is not supported", initNode);
  366. script = origScript;
  367. // Clear the initialization node
  368. initNode = 0;
  369. initScript = script;
  370. #else
  371. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  372. asCParser parser(builder);
  373. int r = parser.ParseVarInit(initScript, initNode);
  374. if( r < 0 )
  375. continue;
  376. initNode = parser.GetScriptNode();
  377. #endif
  378. }
  379. else
  380. {
  381. if( !onlyDefaults )
  382. continue;
  383. }
  384. #ifdef AS_NO_MEMBER_INIT
  385. // The initialization will be done in the asCScriptObject constructor, so
  386. // here we should just validate that the member has a default constructor
  387. if( prop->type.IsObject() &&
  388. !prop->type.IsObjectHandle() &&
  389. (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
  390. prop->type.GetBehaviour()->factory == 0) ||
  391. ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
  392. prop->type.GetBehaviour()->construct == 0 &&
  393. !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
  394. {
  395. // Class has no default factory/constructor.
  396. asCString str;
  397. // TODO: funcdef: asCDataType should have a GetTypeName()
  398. if( prop->type.GetFuncDef() )
  399. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  400. else
  401. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
  402. Error(str, declNode);
  403. }
  404. #else
  405. // Temporarily set the script that is being compiled to where the member initialization is declared.
  406. // The script can be different when including mixin classes from a different script section
  407. asCScriptCode *origScript = script;
  408. script = initScript;
  409. // Add a line instruction with the position of the declaration
  410. LineInstr(byteCode, declNode->tokenPos);
  411. // Compile the initialization
  412. asQWORD constantValue;
  413. asCByteCode bc(engine);
  414. CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  415. byteCode->AddCode(&bc);
  416. script = origScript;
  417. #endif
  418. }
  419. }
  420. }
  421. // Entry
  422. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> &parameterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  423. {
  424. TimeIt("asCCompiler::CompileFunction");
  425. Reset(builder, script, outFunc);
  426. int buildErrors = builder->numErrors;
  427. int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
  428. //--------------------------------------------
  429. // Compile the statement block
  430. if( m_isConstructor )
  431. m_classDecl = classDecl;
  432. // We need to parse the statement block now
  433. asCScriptNode *blockBegin;
  434. // If the function signature was implicit, e.g. virtual property
  435. // accessor, then the received node already is the statement block
  436. if( func->nodeType != snStatementBlock )
  437. blockBegin = func->lastChild;
  438. else
  439. blockBegin = func;
  440. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  441. // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated
  442. asCParser parser(builder);
  443. int r = parser.ParseStatementBlock(script, blockBegin);
  444. if( r < 0 ) return -1;
  445. asCScriptNode *block = parser.GetScriptNode();
  446. // Reserve a label for the cleanup code
  447. nextLabel++;
  448. bool hasReturn;
  449. asCByteCode bc(engine);
  450. LineInstr(&bc, blockBegin->tokenPos);
  451. CompileStatementBlock(block, false, &hasReturn, &bc);
  452. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  453. // Make sure there is a return in all paths (if not return type is void)
  454. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  455. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  456. {
  457. if( hasReturn == false )
  458. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  459. }
  460. //------------------------------------------------
  461. // Concatenate the bytecode
  462. // Insert a JitEntry at the start of the function for JIT compilers
  463. byteCode.InstrPTR(asBC_JitEntry, 0);
  464. if( outFunc->objectType )
  465. {
  466. if( m_isConstructor )
  467. {
  468. if( outFunc->objectType->derivedFrom )
  469. {
  470. // Call the base class' default constructor unless called manually in the code
  471. if( !m_isConstructorCalled )
  472. {
  473. if( outFunc->objectType->derivedFrom->beh.construct )
  474. {
  475. // Initialize members without explicit expression first
  476. CompileMemberInitialization(&byteCode, true);
  477. // Call base class' constructor
  478. asCByteCode tmpBC(engine);
  479. tmpBC.InstrSHORT(asBC_PSF, 0);
  480. tmpBC.Instr(asBC_RDSPtr);
  481. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  482. tmpBC.OptimizeLocally(tempVariableOffsets);
  483. byteCode.AddCode(&tmpBC);
  484. // Add the initialization of the members with explicit expressions
  485. CompileMemberInitialization(&byteCode, false);
  486. }
  487. else
  488. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  489. }
  490. else
  491. {
  492. // Only initialize members that don't have an explicit expression
  493. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  494. CompileMemberInitialization(&byteCode, true);
  495. }
  496. }
  497. else
  498. {
  499. // Add the initialization of the members
  500. CompileMemberInitialization(&byteCode, true);
  501. CompileMemberInitialization(&byteCode, false);
  502. }
  503. }
  504. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  505. if( !m_isConstructor && !outFunc->returnType.IsReference() )
  506. {
  507. // TODO: runtime optimize: If the function is trivial, i.e. doesn't access any outside functions,
  508. // then this is not necessary. If I implement this, then the function needs
  509. // to set a flag so the exception handler doesn't try to release the handle.
  510. // It is not necessary to do this for constructors, as they have no outside references that can be released anyway
  511. // It is not necessary to do this for methods that return references, as the caller is guaranteed to hold a reference to the object
  512. asCByteCode tmpBC(engine);
  513. tmpBC.InstrSHORT(asBC_PSF, 0);
  514. tmpBC.Instr(asBC_RDSPtr);
  515. tmpBC.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  516. tmpBC.OptimizeLocally(tempVariableOffsets);
  517. byteCode.AddCode(&tmpBC);
  518. }
  519. }
  520. // Add the code for the statement block
  521. byteCode.AddCode(&bc);
  522. // Count total variable size
  523. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  524. outFunc->scriptData->variableSpace = varSize;
  525. // Deallocate all local variables
  526. int n;
  527. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  528. {
  529. sVariable *v = variables->variables[n];
  530. if( v->stackOffset > 0 )
  531. {
  532. // Call variables destructors
  533. if( v->name != "return" && v->name != "return address" )
  534. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  535. DeallocateVariable(v->stackOffset);
  536. }
  537. }
  538. // This is the label that return statements jump to
  539. // in order to exit the function
  540. byteCode.Label(0);
  541. // Call destructors for function parameters
  542. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  543. {
  544. sVariable *v = variables->variables[n];
  545. if( v->stackOffset <= 0 )
  546. {
  547. // Call variable destructors here, for variables not yet destroyed
  548. if( v->name != "return" && v->name != "return address" )
  549. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  550. }
  551. // Do not deallocate parameters
  552. }
  553. // Release the object pointer again
  554. if( outFunc->objectType && !m_isConstructor && !outFunc->returnType.IsReference() )
  555. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  556. // Check if the number of labels in the functions isn't too many to be handled
  557. if( nextLabel >= (1<<15) )
  558. Error(TXT_TOO_MANY_JUMP_LABELS, func);
  559. // If there are compile errors, there is no reason to build the final code
  560. if( hasCompileErrors || builder->numErrors != buildErrors )
  561. return -1;
  562. // At this point there should be no variables allocated
  563. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  564. // Remove the variable scope
  565. RemoveVariableScope();
  566. byteCode.Ret(-stackPos);
  567. FinalizeFunction();
  568. #ifdef AS_DEBUG
  569. // DEBUG: output byte code
  570. if( outFunc->objectType )
  571. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  572. else
  573. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  574. #endif
  575. return 0;
  576. }
  577. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  578. {
  579. if( !type.IsObject() )
  580. return 0;
  581. // CallCopyConstructor should not be called for object handles.
  582. asASSERT( !type.IsObjectHandle() );
  583. asCArray<asSExprContext*> args;
  584. args.PushLast(arg);
  585. // The reference parameter must be pushed on the stack
  586. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  587. // Since we're calling the copy constructor, we have to trust the function to not do
  588. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  589. // copies of the argument in order to guarantee safety.
  590. if( type.GetObjectType()->flags & asOBJ_REF )
  591. {
  592. asSExprContext ctx(engine);
  593. int func = 0;
  594. asSTypeBehaviour *beh = type.GetBehaviour();
  595. if( beh ) func = beh->copyfactory;
  596. if( func > 0 )
  597. {
  598. if( !isGlobalVar )
  599. {
  600. // Call factory and store the handle in the given variable
  601. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  602. // Pop the reference left by the function call
  603. ctx.bc.Instr(asBC_PopPtr);
  604. }
  605. else
  606. {
  607. // Call factory
  608. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  609. // Store the returned handle in the global variable
  610. ctx.bc.Instr(asBC_RDSPtr);
  611. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  612. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  613. ctx.bc.Instr(asBC_PopPtr);
  614. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  615. }
  616. bc->AddCode(&ctx.bc);
  617. return 0;
  618. }
  619. }
  620. else
  621. {
  622. asSTypeBehaviour *beh = type.GetBehaviour();
  623. int func = beh ? beh->copyconstruct : 0;
  624. if( func > 0 )
  625. {
  626. // Push the address where the object will be stored on the stack, before the argument
  627. // TODO: When the context is serializable this probably has to be changed, since this
  628. // pointer can remain on the stack while the context is suspended. There is no
  629. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  630. asCByteCode tmp(engine);
  631. if( isGlobalVar )
  632. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  633. else if( isObjectOnHeap )
  634. tmp.InstrSHORT(asBC_PSF, (short)offset);
  635. tmp.AddCode(bc);
  636. bc->AddCode(&tmp);
  637. // When the object is allocated on the stack the object pointer
  638. // must be pushed on the stack after the arguments
  639. if( !isObjectOnHeap )
  640. {
  641. asASSERT( !isGlobalVar );
  642. bc->InstrSHORT(asBC_PSF, (short)offset);
  643. if( derefDest )
  644. {
  645. // The variable is a reference to the real location, so we need to dereference it
  646. bc->Instr(asBC_RDSPtr);
  647. }
  648. }
  649. asSExprContext ctx(engine);
  650. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  651. bc->AddCode(&ctx.bc);
  652. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  653. // Mark the object as initialized
  654. if( !isObjectOnHeap )
  655. bc->ObjInfo(offset, asOBJ_INIT);
  656. return 0;
  657. }
  658. }
  659. // Class has no copy constructor/factory.
  660. asCString str;
  661. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  662. Error(str, node);
  663. return -1;
  664. }
  665. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  666. {
  667. if( !type.IsObject() || type.IsObjectHandle() )
  668. return 0;
  669. if( type.GetObjectType()->flags & asOBJ_REF )
  670. {
  671. asSExprContext ctx(engine);
  672. ctx.exprNode = node;
  673. int func = 0;
  674. asSTypeBehaviour *beh = type.GetBehaviour();
  675. if( beh ) func = beh->factory;
  676. if( func > 0 )
  677. {
  678. if( isVarGlobOrMem == 0 )
  679. {
  680. // Call factory and store the handle in the given variable
  681. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  682. // Pop the reference left by the function call
  683. ctx.bc.Instr(asBC_PopPtr);
  684. }
  685. else
  686. {
  687. // Call factory
  688. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  689. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  690. // instead of first storing it in a local variable and then copying it to the
  691. // destination.
  692. if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
  693. {
  694. // Only dereference the variable if not a scoped type
  695. ctx.bc.Instr(asBC_RDSPtr);
  696. }
  697. if( isVarGlobOrMem == 1 )
  698. {
  699. // Store the returned handle in the global variable
  700. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  701. }
  702. else
  703. {
  704. // Store the returned handle in the class member
  705. ctx.bc.InstrSHORT(asBC_PSF, 0);
  706. ctx.bc.Instr(asBC_RDSPtr);
  707. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  708. }
  709. if( type.GetObjectType()->flags & asOBJ_SCOPED )
  710. {
  711. // For scoped typed we must move the reference from the local
  712. // variable rather than copy it as there is no AddRef behaviour
  713. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  714. // Clear the local variable so the reference isn't released
  715. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  716. }
  717. else
  718. {
  719. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  720. }
  721. ctx.bc.Instr(asBC_PopPtr);
  722. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  723. }
  724. bc->AddCode(&ctx.bc);
  725. return 0;
  726. }
  727. }
  728. else
  729. {
  730. asSTypeBehaviour *beh = type.GetBehaviour();
  731. int func = 0;
  732. if( beh ) func = beh->construct;
  733. // Allocate and initialize with the default constructor
  734. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  735. {
  736. if( !isObjectOnHeap )
  737. {
  738. asASSERT( isVarGlobOrMem == 0 );
  739. // There is nothing to do if there is no function,
  740. // as the memory is already allocated on the stack
  741. if( func )
  742. {
  743. // Call the constructor as a normal function
  744. bc->InstrSHORT(asBC_PSF, (short)offset);
  745. if( derefDest )
  746. bc->Instr(asBC_RDSPtr);
  747. asSExprContext ctx(engine);
  748. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  749. bc->AddCode(&ctx.bc);
  750. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  751. // Mark the object as initialized
  752. bc->ObjInfo(offset, asOBJ_INIT);
  753. }
  754. }
  755. else
  756. {
  757. if( isVarGlobOrMem == 0 )
  758. bc->InstrSHORT(asBC_PSF, (short)offset);
  759. else if( isVarGlobOrMem == 1 )
  760. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  761. else
  762. {
  763. bc->InstrSHORT(asBC_PSF, 0);
  764. bc->Instr(asBC_RDSPtr);
  765. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  766. }
  767. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  768. }
  769. return 0;
  770. }
  771. }
  772. // Class has no default factory/constructor.
  773. asCString str;
  774. // TODO: funcdef: asCDataType should have a GetTypeName()
  775. if( type.GetFuncDef() )
  776. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  777. else
  778. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  779. Error(str, node);
  780. return -1;
  781. }
  782. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  783. {
  784. if( !type.IsReference() )
  785. {
  786. // Call destructor for the data type
  787. if( type.IsObject() )
  788. {
  789. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  790. if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN )
  791. return;
  792. if( isObjectOnHeap || type.IsObjectHandle() )
  793. {
  794. // Free the memory
  795. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  796. }
  797. else
  798. {
  799. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  800. if( type.GetBehaviour()->destruct )
  801. {
  802. // Call the destructor as a regular function
  803. asSExprContext ctx(engine);
  804. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  805. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  806. ctx.bc.OptimizeLocally(tempVariableOffsets);
  807. bc->AddCode(&ctx.bc);
  808. }
  809. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  810. // Mark the object as destroyed
  811. bc->ObjInfo(offset, asOBJ_UNINIT);
  812. }
  813. }
  814. }
  815. }
  816. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  817. {
  818. int r, c;
  819. script->ConvertPosToRowCol(pos, &r, &c);
  820. bc->Line(r, c, script->idx);
  821. }
  822. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  823. {
  824. *hasReturn = false;
  825. bool isFinished = false;
  826. bool hasUnreachableCode = false;
  827. bool hasReturnBefore = false;
  828. if( ownVariableScope )
  829. {
  830. bc->Block(true);
  831. AddVariableScope();
  832. }
  833. asCScriptNode *node = block->firstChild;
  834. while( node )
  835. {
  836. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  837. {
  838. // Empty statements don't count
  839. if( node->nodeType != snExpressionStatement || node->firstChild )
  840. {
  841. hasUnreachableCode = true;
  842. Warning(TXT_UNREACHABLE_CODE, node);
  843. }
  844. if( *hasReturn )
  845. hasReturnBefore = true;
  846. }
  847. if( node->nodeType == snBreak || node->nodeType == snContinue )
  848. isFinished = true;
  849. asCByteCode statement(engine);
  850. if( node->nodeType == snDeclaration )
  851. CompileDeclaration(node, &statement);
  852. else
  853. CompileStatement(node, hasReturn, &statement);
  854. // Ignore missing returns in unreachable code paths
  855. if( !(*hasReturn) && hasReturnBefore )
  856. *hasReturn = true;
  857. LineInstr(bc, node->tokenPos);
  858. bc->AddCode(&statement);
  859. if( !hasCompileErrors )
  860. {
  861. asASSERT( tempVariables.GetLength() == 0 );
  862. asASSERT( reservedVariables.GetLength() == 0 );
  863. }
  864. node = node->next;
  865. }
  866. if( ownVariableScope )
  867. {
  868. // Deallocate variables in this block, in reverse order
  869. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  870. {
  871. sVariable *v = variables->variables[n];
  872. // Call variable destructors here, for variables not yet destroyed
  873. // If the block is terminated with a break, continue, or
  874. // return the variables are already destroyed
  875. if( !isFinished && !*hasReturn )
  876. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  877. // Don't deallocate function parameters
  878. if( v->stackOffset > 0 )
  879. DeallocateVariable(v->stackOffset);
  880. }
  881. RemoveVariableScope();
  882. bc->Block(false);
  883. }
  884. }
  885. // Entry
  886. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  887. {
  888. Reset(builder, script, outFunc);
  889. // Add a variable scope (even though variables can't be declared)
  890. AddVariableScope();
  891. gvar->isPureConstant = false;
  892. // Parse the initialization nodes
  893. asCParser parser(builder);
  894. if( node )
  895. {
  896. int r = parser.ParseVarInit(script, node);
  897. if( r < 0 )
  898. return r;
  899. node = parser.GetScriptNode();
  900. }
  901. // Compile the expression
  902. asSExprContext ctx(engine);
  903. asQWORD constantValue;
  904. if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->idNode, gvar->index, &constantValue, 1) )
  905. {
  906. // Should the variable be marked as pure constant?
  907. if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
  908. {
  909. gvar->isPureConstant = true;
  910. gvar->constantValue = constantValue;
  911. }
  912. }
  913. // Concatenate the bytecode
  914. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  915. // Add information on the line number for the global variable
  916. size_t pos = 0;
  917. if( gvar->idNode )
  918. pos = gvar->idNode->tokenPos;
  919. else if( gvar->nextNode )
  920. pos = gvar->nextNode->tokenPos;
  921. LineInstr(&byteCode, pos);
  922. // Reserve space for all local variables
  923. outFunc->scriptData->variableSpace = varSize;
  924. ctx.bc.OptimizeLocally(tempVariableOffsets);
  925. byteCode.AddCode(&ctx.bc);
  926. // Deallocate variables in this block, in reverse order
  927. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  928. {
  929. sVariable *v = variables->variables[n];
  930. // Call variable destructors here, for variables not yet destroyed
  931. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  932. DeallocateVariable(v->stackOffset);
  933. }
  934. if( hasCompileErrors ) return -1;
  935. // At this point there should be no variables allocated
  936. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  937. // Remove the variable scope again
  938. RemoveVariableScope();
  939. byteCode.Ret(0);
  940. FinalizeFunction();
  941. #ifdef AS_DEBUG
  942. // DEBUG: output byte code
  943. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  944. #endif
  945. return 0;
  946. }
  947. void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
  948. {
  949. // Don't do anything if this is not a deferred global function
  950. if( !ctx->IsGlobalFunc() )
  951. return;
  952. // Determine the namespace
  953. asSNameSpace *ns = 0;
  954. asCString name = "";
  955. int pos = ctx->methodName.FindLast("::");
  956. if( pos >= 0 )
  957. {
  958. asCString nsName = ctx->methodName.SubString(0, pos+2);
  959. // Cut off the ::
  960. if( nsName.GetLength() > 2 )
  961. nsName.SetLength(nsName.GetLength()-2);
  962. ns = DetermineNameSpace(nsName);
  963. name = ctx->methodName.SubString(pos+2);
  964. }
  965. else
  966. {
  967. DetermineNameSpace("");
  968. name = ctx->methodName;
  969. }
  970. asCArray<int> funcs;
  971. if( ns )
  972. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  973. // CompileVariableAccess should guarantee that at least one function is exists
  974. asASSERT( funcs.GetLength() > 0 );
  975. if( funcs.GetLength() > 1 )
  976. {
  977. asCString str;
  978. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  979. Error(str, node);
  980. // Fall through so the compiler can continue as if only one function was matching
  981. }
  982. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  983. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  984. outFunc->IsShared() )
  985. {
  986. asCString msg;
  987. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  988. Error(msg, node);
  989. // Fall through so the compiler can continue anyway
  990. }
  991. // Push the function pointer on the stack
  992. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  993. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  994. ctx->type.dataType.MakeHandle(true);
  995. ctx->type.isExplicitHandle = true;
  996. ctx->methodName = "";
  997. }
  998. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  999. {
  1000. asCDataType param = *paramType;
  1001. if( paramType->GetTokenType() == ttQuestion )
  1002. {
  1003. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1004. DetermineSingleFunc(ctx, node);
  1005. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1006. param = ctx->type.dataType;
  1007. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1008. // If value assign is disabled for reference types, then make
  1009. // sure to always pass the handle to ? parameters
  1010. if( builder->engine->ep.disallowValueAssignForRefType &&
  1011. ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1012. {
  1013. param.MakeHandle(true);
  1014. }
  1015. param.MakeReference(paramType->IsReference());
  1016. param.MakeReadOnly(paramType->IsReadOnly());
  1017. }
  1018. else
  1019. param = *paramType;
  1020. asCDataType dt = param;
  1021. // Need to protect arguments by reference
  1022. if( isFunction && dt.IsReference() )
  1023. {
  1024. // Allocate a temporary variable of the same type as the argument
  1025. dt.MakeReference(false);
  1026. dt.MakeReadOnly(false);
  1027. int offset;
  1028. if( refType == 1 ) // &in
  1029. {
  1030. ProcessPropertyGetAccessor(ctx, node);
  1031. // Add the type id as hidden arg if the parameter is a ? type
  1032. if( paramType->GetTokenType() == ttQuestion )
  1033. {
  1034. asCByteCode tmpBC(engine);
  1035. // Place the type id on the stack as a hidden parameter
  1036. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1037. // Insert the code before the expression code
  1038. tmpBC.AddCode(&ctx->bc);
  1039. ctx->bc.AddCode(&tmpBC);
  1040. }
  1041. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1042. // Even if the same variable is passed in another argument as non-const then there is no problem
  1043. if( dt.IsPrimitive() || dt.IsNullHandle() )
  1044. {
  1045. IsVariableInitialized(&ctx->type, node);
  1046. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1047. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1048. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1049. ConvertToTempVariable(ctx);
  1050. PushVariableOnStack(ctx, true);
  1051. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1052. }
  1053. else
  1054. {
  1055. IsVariableInitialized(&ctx->type, node);
  1056. if( !isMakingCopy )
  1057. {
  1058. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true);
  1059. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  1060. {
  1061. asCString str;
  1062. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  1063. Error(str, node);
  1064. ctx->type.Set(param);
  1065. }
  1066. }
  1067. // If the argument already is a temporary
  1068. // variable we don't need to allocate another
  1069. // If the parameter is read-only and the object already is a local
  1070. // variable then it is not necessary to make a copy either
  1071. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
  1072. {
  1073. // Make sure the variable is not used in the expression
  1074. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1075. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  1076. // Allocate and construct the temporary object
  1077. asCByteCode tmpBC(engine);
  1078. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1079. // Insert the code before the expression code
  1080. tmpBC.AddCode(&ctx->bc);
  1081. ctx->bc.AddCode(&tmpBC);
  1082. // Assign the evaluated expression to the temporary variable
  1083. PrepareForAssignment(&dt, ctx, node, true);
  1084. dt.MakeReference(IsVariableOnHeap(offset));
  1085. asCTypeInfo type;
  1086. type.Set(dt);
  1087. type.isTemporary = true;
  1088. type.stackOffset = (short)offset;
  1089. if( dt.IsObjectHandle() )
  1090. type.isExplicitHandle = true;
  1091. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1092. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  1093. ctx->bc.Instr(asBC_PopPtr);
  1094. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  1095. ctx->type.Set(dt);
  1096. ctx->type.isTemporary = true;
  1097. ctx->type.stackOffset = offset;
  1098. if( dt.IsObjectHandle() )
  1099. ctx->type.isExplicitHandle = true;
  1100. ctx->type.dataType.MakeReference(false);
  1101. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1102. if( dt.IsObject() && !dt.IsObjectHandle() )
  1103. ctx->bc.Instr(asBC_RDSPtr);
  1104. if( paramType->IsReadOnly() )
  1105. ctx->type.dataType.MakeReadOnly(true);
  1106. }
  1107. else if( isMakingCopy )
  1108. {
  1109. // We must guarantee that the address to the value is on the stack
  1110. if( ctx->type.dataType.IsObject() &&
  1111. !ctx->type.dataType.IsObjectHandle() &&
  1112. ctx->type.dataType.IsReference() )
  1113. Dereference(ctx, true);
  1114. }
  1115. }
  1116. }
  1117. else if( refType == 2 ) // &out
  1118. {
  1119. // Add the type id as hidden arg if the parameter is a ? type
  1120. if( paramType->GetTokenType() == ttQuestion )
  1121. {
  1122. asCByteCode tmpBC(engine);
  1123. // Place the type id on the stack as a hidden parameter
  1124. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1125. // Insert the code before the expression code
  1126. tmpBC.AddCode(&ctx->bc);
  1127. ctx->bc.AddCode(&tmpBC);
  1128. }
  1129. // Make sure the variable is not used in the expression
  1130. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1131. if( dt.IsPrimitive() )
  1132. {
  1133. ctx->type.SetVariable(dt, offset, true);
  1134. PushVariableOnStack(ctx, true);
  1135. }
  1136. else
  1137. {
  1138. // Allocate and construct the temporary object
  1139. asCByteCode tmpBC(engine);
  1140. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1141. // Insert the code before the expression code
  1142. tmpBC.AddCode(&ctx->bc);
  1143. ctx->bc.AddCode(&tmpBC);
  1144. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  1145. asCTypeInfo type;
  1146. type.Set(dt);
  1147. type.isTemporary = true;
  1148. type.stackOffset = (short)offset;
  1149. ctx->type = type;
  1150. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1151. if( dt.IsObject() && !dt.IsObjectHandle() )
  1152. ctx->bc.Instr(asBC_RDSPtr);
  1153. }
  1154. // After the function returns the temporary variable will
  1155. // be assigned to the expression, if it is a valid lvalue
  1156. }
  1157. else if( refType == asTM_INOUTREF )
  1158. {
  1159. ProcessPropertyGetAccessor(ctx, node);
  1160. // Add the type id as hidden arg if the parameter is a ? type
  1161. if( paramType->GetTokenType() == ttQuestion )
  1162. {
  1163. asCByteCode tmpBC(engine);
  1164. // Place the type id on the stack as a hidden parameter
  1165. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1166. // Insert the code before the expression code
  1167. tmpBC.AddCode(&ctx->bc);
  1168. ctx->bc.AddCode(&tmpBC);
  1169. }
  1170. // Literal constants cannot be passed to inout ref arguments
  1171. if( !ctx->type.isVariable && ctx->type.isConstant )
  1172. {
  1173. Error(TXT_NOT_VALID_REFERENCE, node);
  1174. }
  1175. // Only objects that support object handles
  1176. // can be guaranteed to be safe. Local variables are
  1177. // already safe, so there is no need to add an extra
  1178. // references
  1179. if( !engine->ep.allowUnsafeReferences &&
  1180. !ctx->type.isVariable &&
  1181. ctx->type.dataType.IsObject() &&
  1182. !ctx->type.dataType.IsObjectHandle() &&
  1183. ((ctx->type.dataType.GetBehaviour()->addref &&
  1184. ctx->type.dataType.GetBehaviour()->release) ||
  1185. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1186. {
  1187. // Store a handle to the object as local variable
  1188. asSExprContext tmp(engine);
  1189. asCDataType dt = ctx->type.dataType;
  1190. dt.MakeHandle(true);
  1191. dt.MakeReference(false);
  1192. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1193. // Copy the handle
  1194. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1195. ctx->bc.Instr(asBC_RDSPtr);
  1196. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1197. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1198. ctx->bc.Instr(asBC_PopPtr);
  1199. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1200. dt.MakeHandle(false);
  1201. dt.MakeReference(true);
  1202. // Release previous temporary variable stored in the context (if any)
  1203. if( ctx->type.isTemporary )
  1204. {
  1205. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1206. }
  1207. ctx->type.SetVariable(dt, offset, true);
  1208. }
  1209. // Make sure the reference to the value is on the stack
  1210. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1211. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1212. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1213. Dereference(ctx, true);
  1214. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1215. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1216. else if( ctx->type.dataType.IsPrimitive() )
  1217. ctx->bc.Instr(asBC_PshRPtr);
  1218. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1219. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1220. }
  1221. }
  1222. else
  1223. {
  1224. ProcessPropertyGetAccessor(ctx, node);
  1225. if( dt.IsPrimitive() )
  1226. {
  1227. IsVariableInitialized(&ctx->type, node);
  1228. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1229. // Implicitly convert primitives to the parameter type
  1230. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1231. if( ctx->type.isVariable )
  1232. {
  1233. PushVariableOnStack(ctx, dt.IsReference());
  1234. }
  1235. else if( ctx->type.isConstant )
  1236. {
  1237. ConvertToVariable(ctx);
  1238. PushVariableOnStack(ctx, dt.IsReference());
  1239. }
  1240. }
  1241. else
  1242. {
  1243. IsVariableInitialized(&ctx->type, node);
  1244. // Implicitly convert primitives to the parameter type
  1245. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1246. // Was the conversion successful?
  1247. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1248. {
  1249. asCString str;
  1250. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1251. Error(str, node);
  1252. ctx->type.Set(dt);
  1253. }
  1254. if( dt.IsObjectHandle() )
  1255. ctx->type.isExplicitHandle = true;
  1256. if( dt.IsObject() )
  1257. {
  1258. if( !dt.IsReference() )
  1259. {
  1260. // Objects passed by value must be placed in temporary variables
  1261. // so that they are guaranteed to not be referenced anywhere else.
  1262. // The object must also be allocated on the heap, as the memory will
  1263. // be deleted by in as_callfunc_xxx.
  1264. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1265. // Local variables doesn't need to be copied into
  1266. // a temp if we're already compiling an assignment
  1267. if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
  1268. PrepareTemporaryObject(node, ctx, true);
  1269. // The implicit conversion shouldn't convert the object to
  1270. // non-reference yet. It will be dereferenced just before the call.
  1271. // Otherwise the object might be missed by the exception handler.
  1272. dt.MakeReference(true);
  1273. }
  1274. else
  1275. {
  1276. // An object passed by reference should place the pointer to
  1277. // the object on the stack.
  1278. dt.MakeReference(false);
  1279. }
  1280. }
  1281. }
  1282. }
  1283. // Don't put any pointer on the stack yet
  1284. if( param.IsReference() || param.IsObject() )
  1285. {
  1286. // &inout parameter may leave the reference on the stack already
  1287. if( refType != 3 )
  1288. {
  1289. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1290. if( ctx->type.isVariable || ctx->type.isTemporary )
  1291. {
  1292. ctx->bc.Instr(asBC_PopPtr);
  1293. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1294. ProcessDeferredParams(ctx);
  1295. }
  1296. }
  1297. }
  1298. }
  1299. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1300. {
  1301. // When a match has been found, compile the final byte code using correct parameter types
  1302. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1303. // If the function being called is the opAssign or copy constructor for the same type
  1304. // as the argument, then we should avoid making temporary copy of the argument
  1305. bool makingCopy = false;
  1306. if( descr->parameterTypes.GetLength() == 1 &&
  1307. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1308. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1309. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1310. makingCopy = true;
  1311. // Add code for arguments
  1312. asSExprContext e(engine);
  1313. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1314. {
  1315. // Make sure PrepareArgument doesn't use any variable that is already
  1316. // being used by any of the following argument expressions
  1317. int l = int(reservedVariables.GetLength());
  1318. for( int m = n-1; m >= 0; m-- )
  1319. args[m]->bc.GetVarsUsed(reservedVariables);
  1320. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1321. reservedVariables.SetLength(l);
  1322. }
  1323. bc->AddCode(&e.bc);
  1324. }
  1325. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1326. {
  1327. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1328. int offset = 0;
  1329. if( addOneToOffset )
  1330. offset += AS_PTR_SIZE;
  1331. // The address of where the return value should be stored is push on top of the arguments
  1332. if( descr->DoesReturnOnStack() )
  1333. offset += AS_PTR_SIZE;
  1334. #ifdef AS_DEBUG
  1335. // If the function being called is the opAssign or copy constructor for the same type
  1336. // as the argument, then we should avoid making temporary copy of the argument
  1337. bool makingCopy = false;
  1338. if( descr->parameterTypes.GetLength() == 1 &&
  1339. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1340. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1341. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1342. makingCopy = true;
  1343. #endif
  1344. // Move the objects that are sent by value to the stack just before the call
  1345. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1346. {
  1347. if( descr->parameterTypes[n].IsReference() )
  1348. {
  1349. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1350. {
  1351. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1352. {
  1353. #ifdef AS_DEBUG
  1354. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1355. #endif
  1356. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1357. {
  1358. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1359. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1360. // as the value allocated on the stack is guaranteed to be safe
  1361. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1362. else
  1363. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1364. }
  1365. }
  1366. if( args[n]->type.dataType.IsObjectHandle() )
  1367. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1368. }
  1369. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1370. {
  1371. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1372. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1373. {
  1374. // Send the object as a reference to the object,
  1375. // and not to the variable holding the object
  1376. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1377. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1378. // as the value allocated on the stack is guaranteed to be safe
  1379. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1380. else
  1381. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1382. }
  1383. else
  1384. {
  1385. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1386. }
  1387. }
  1388. }
  1389. else if( descr->parameterTypes[n].IsObject() )
  1390. {
  1391. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1392. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1393. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1394. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1395. // The temporary variable must not be freed as it will no longer hold an object
  1396. DeallocateVariable(args[n]->type.stackOffset);
  1397. args[n]->type.isTemporary = false;
  1398. }
  1399. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1400. }
  1401. }
  1402. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1403. {
  1404. asASSERT(node->nodeType == snArgList);
  1405. // Count arguments
  1406. asCScriptNode *arg = node->firstChild;
  1407. int argCount = 0;
  1408. while( arg )
  1409. {
  1410. argCount++;
  1411. arg = arg->next;
  1412. }
  1413. // Prepare the arrays
  1414. args.SetLength(argCount);
  1415. int n;
  1416. for( n = 0; n < argCount; n++ )
  1417. args[n] = 0;
  1418. n = argCount-1;
  1419. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1420. bool anyErrors = false;
  1421. arg = node->lastChild;
  1422. while( arg )
  1423. {
  1424. asSExprContext expr(engine);
  1425. int r = CompileAssignment(arg, &expr);
  1426. if( r < 0 ) anyErrors = true;
  1427. args[n] = asNEW(asSExprContext)(engine);
  1428. if( args[n] == 0 )
  1429. {
  1430. // Out of memory
  1431. return -1;
  1432. }
  1433. MergeExprBytecodeAndType(args[n], &expr);
  1434. n--;
  1435. arg = arg->prev;
  1436. }
  1437. return anyErrors ? -1 : 0;
  1438. }
  1439. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1440. {
  1441. bool anyErrors = false;
  1442. asCArray<int> varsUsed;
  1443. int explicitArgs = (int)args.GetLength();
  1444. for( int p = 0; p < explicitArgs; p++ )
  1445. args[p]->bc.GetVarsUsed(varsUsed);
  1446. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1447. args.SetLength(func->parameterTypes.GetLength());
  1448. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1449. args[c] = 0;
  1450. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1451. {
  1452. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1453. // Parse the default arg string
  1454. asCParser parser(builder);
  1455. asCScriptCode code;
  1456. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1457. int r = parser.ParseExpression(&code);
  1458. if( r < 0 )
  1459. {
  1460. asCString msg;
  1461. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1462. Error(msg, node);
  1463. anyErrors = true;
  1464. continue;
  1465. }
  1466. asCScriptNode *arg = parser.GetScriptNode();
  1467. // Temporarily set the script code to the default arg expression
  1468. asCScriptCode *origScript = script;
  1469. script = &code;
  1470. // Don't allow the expression to access local variables
  1471. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function that is called
  1472. isCompilingDefaultArg = true;
  1473. asSExprContext expr(engine);
  1474. r = CompileExpression(arg, &expr);
  1475. // Don't allow address of class method
  1476. if( expr.methodName != "" )
  1477. {
  1478. // TODO: Improve error message
  1479. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1480. r = -1;
  1481. }
  1482. // Make sure the expression can be implicitly converted to the parameter type
  1483. if( r >= 0 )
  1484. {
  1485. asCArray<int> funcs;
  1486. funcs.PushLast(func->id);
  1487. asCArray<asSOverloadCandidate> matches;
  1488. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1489. {
  1490. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1491. r = -1;
  1492. }
  1493. }
  1494. isCompilingDefaultArg = false;
  1495. script = origScript;
  1496. if( r < 0 )
  1497. {
  1498. asCString msg;
  1499. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1500. Error(msg, node);
  1501. anyErrors = true;
  1502. continue;
  1503. }
  1504. args[n] = asNEW(asSExprContext)(engine);
  1505. if( args[n] == 0 )
  1506. {
  1507. // Out of memory
  1508. return -1;
  1509. }
  1510. MergeExprBytecodeAndType(args[n], &expr);
  1511. // Make sure the default arg expression doesn't end up
  1512. // with a variable that is used in a previous expression
  1513. if( args[n]->type.isVariable )
  1514. {
  1515. int offset = args[n]->type.stackOffset;
  1516. if( varsUsed.Exists(offset) )
  1517. {
  1518. // Release the current temporary variable
  1519. ReleaseTemporaryVariable(args[n]->type, 0);
  1520. asCDataType dt = args[n]->type.dataType;
  1521. dt.MakeReference(false);
  1522. // Reserve all variables already used in the expression so none of them will be used
  1523. asCArray<int> used;
  1524. args[n]->bc.GetVarsUsed(used);
  1525. size_t prevReserved = reservedVariables.GetLength();
  1526. reservedVariables.Concatenate(used);
  1527. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1528. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1529. reservedVariables.SetLength(prevReserved);
  1530. // Replace the variable in the expression
  1531. args[n]->bc.ExchangeVar(offset, newOffset);
  1532. args[n]->type.stackOffset = (short)newOffset;
  1533. args[n]->type.isTemporary = true;
  1534. args[n]->type.isVariable = true;
  1535. }
  1536. }
  1537. }
  1538. return anyErrors ? -1 : 0;
  1539. }
  1540. asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1541. {
  1542. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1543. asUINT cost = 0;
  1544. asUINT n;
  1545. if( funcs.GetLength() > 0 )
  1546. {
  1547. // Check the number of parameters in the found functions
  1548. for( n = 0; n < funcs.GetLength(); ++n )
  1549. {
  1550. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1551. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1552. {
  1553. bool noMatch = true;
  1554. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1555. {
  1556. // Count the number of default args
  1557. asUINT defaultArgs = 0;
  1558. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1559. if( desc->defaultArgs[d] )
  1560. defaultArgs++;
  1561. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1562. noMatch = false;
  1563. }
  1564. if( noMatch )
  1565. {
  1566. // remove it from the list
  1567. if( n == funcs.GetLength()-1 )
  1568. funcs.PopLast();
  1569. else
  1570. funcs[n] = funcs.PopLast();
  1571. n--;
  1572. }
  1573. }
  1574. }
  1575. // Match functions with the parameters, and discard those that do not match
  1576. asCArray<asSOverloadCandidate> matchingFuncs;
  1577. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1578. for ( n = 0; n < funcs.GetLength(); ++n )
  1579. {
  1580. matchingFuncs[n].funcId = funcs[n];
  1581. matchingFuncs[n].cost = 0;
  1582. }
  1583. for( n = 0; n < args.GetLength(); ++n )
  1584. {
  1585. asCArray<asSOverloadCandidate> tempFuncs;
  1586. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1587. // Intersect the found functions with the list of matching functions
  1588. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1589. {
  1590. asUINT c;
  1591. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1592. {
  1593. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1594. {
  1595. // Sum argument cost
  1596. matchingFuncs[f].cost += tempFuncs[c].cost;
  1597. break;
  1598. } // End if match
  1599. }
  1600. // Was the function a match?
  1601. if( c == tempFuncs.GetLength() )
  1602. {
  1603. // No, remove it from the list
  1604. if( f == matchingFuncs.GetLength()-1 )
  1605. matchingFuncs.PopLast();
  1606. else
  1607. matchingFuncs[f] = matchingFuncs.PopLast();
  1608. f--;
  1609. }
  1610. }
  1611. }
  1612. // Select the overload(s) with the lowest overall cost
  1613. funcs.SetLength(0);
  1614. asUINT bestCost = asUINT(-1);
  1615. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  1616. {
  1617. cost = matchingFuncs[n].cost;
  1618. if( cost < bestCost )
  1619. {
  1620. funcs.SetLength(0);
  1621. bestCost = cost;
  1622. }
  1623. if( cost == bestCost )
  1624. funcs.PushLast( matchingFuncs[n].funcId );
  1625. }
  1626. // Cost returned is equivalent to the best cost discovered
  1627. cost = bestCost;
  1628. }
  1629. if( !isConstMethod )
  1630. FilterConst(funcs);
  1631. if( funcs.GetLength() != 1 && !silent )
  1632. {
  1633. // Build a readable string of the function with parameter types
  1634. asCString str;
  1635. if( scope != "" )
  1636. {
  1637. if( scope == "::" )
  1638. str = scope;
  1639. else
  1640. str = scope + "::";
  1641. }
  1642. str += name;
  1643. str += "(";
  1644. if( args.GetLength() )
  1645. {
  1646. if( args[0]->methodName != "" )
  1647. str += args[0]->methodName;
  1648. else
  1649. str += args[0]->type.dataType.Format();
  1650. }
  1651. for( n = 1; n < args.GetLength(); n++ )
  1652. {
  1653. str += ", ";
  1654. if( args[n]->methodName != "" )
  1655. str += args[n]->methodName;
  1656. else
  1657. str += args[n]->type.dataType.Format();
  1658. }
  1659. str += ")";
  1660. if( isConstMethod )
  1661. str += " const";
  1662. if( objectType && scope == "" )
  1663. str = objectType->name + "::" + str;
  1664. if( funcs.GetLength() == 0 )
  1665. {
  1666. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1667. Error(str, node);
  1668. // Print the list of candidates
  1669. if( origFuncs.GetLength() > 0 )
  1670. {
  1671. int r = 0, c = 0;
  1672. asASSERT( node );
  1673. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1674. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1675. PrintMatchingFuncs(origFuncs, node);
  1676. }
  1677. }
  1678. else
  1679. {
  1680. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1681. Error(str, node);
  1682. PrintMatchingFuncs(funcs, node);
  1683. }
  1684. }
  1685. return cost;
  1686. }
  1687. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1688. {
  1689. // Get the data type
  1690. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
  1691. // Declare all variables in this declaration
  1692. asCScriptNode *node = decl->firstChild->next;
  1693. while( node )
  1694. {
  1695. // Is the type allowed?
  1696. if( !type.CanBeInstanciated() )
  1697. {
  1698. asCString str;
  1699. // TODO: Change to "'type' cannot be declared as variable"
  1700. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1701. Error(str, node);
  1702. // Use int instead to avoid further problems
  1703. type = asCDataType::CreatePrimitive(ttInt, false);
  1704. }
  1705. // A shared object may not declare variables of non-shared types
  1706. if( outFunc->IsShared() )
  1707. {
  1708. asCObjectType *ot = type.GetObjectType();
  1709. if( ot && !ot->IsShared() )
  1710. {
  1711. asCString msg;
  1712. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1713. Error(msg, decl);
  1714. }
  1715. }
  1716. // Get the name of the identifier
  1717. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1718. // Verify that the name isn't used by a dynamic data type
  1719. if( engine->GetObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  1720. {
  1721. asCString str;
  1722. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1723. Error(str, node);
  1724. }
  1725. int offset = AllocateVariable(type, false);
  1726. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1727. {
  1728. // TODO: It might be an out-of-memory too
  1729. asCString str;
  1730. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1731. Error(str, node);
  1732. // Don't continue after this error, as it will just
  1733. // lead to more errors that are likely false
  1734. return;
  1735. }
  1736. // Add marker that the variable has been declared
  1737. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  1738. outFunc->AddVariable(name, type, offset);
  1739. // Keep the node for the variable decl
  1740. asCScriptNode *varNode = node;
  1741. node = node->next;
  1742. if( node == 0 || node->nodeType == snIdentifier )
  1743. {
  1744. // Initialize with default constructor
  1745. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  1746. }
  1747. else
  1748. {
  1749. // Compile the initialization expression
  1750. asQWORD constantValue = 0;
  1751. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0) )
  1752. {
  1753. // Check if the variable should be marked as pure constant
  1754. if( type.IsPrimitive() && type.IsReadOnly() )
  1755. {
  1756. sVariable *v = variables->GetVariable(name.AddressOf());
  1757. v->isPureConstant = true;
  1758. v->constantValue = constantValue;
  1759. }
  1760. }
  1761. node = node->next;
  1762. }
  1763. }
  1764. bc->OptimizeLocally(tempVariableOffsets);
  1765. }
  1766. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem)
  1767. {
  1768. bool isConstantExpression = false;
  1769. if( node && node->nodeType == snArgList )
  1770. {
  1771. // Make sure it is an object and not a handle
  1772. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1773. {
  1774. Error(TXT_MUST_BE_OBJECT, node);
  1775. }
  1776. else
  1777. {
  1778. // Compile the arguments
  1779. asCArray<asSExprContext *> args;
  1780. if( CompileArgumentList(node, args) >= 0 )
  1781. {
  1782. // Find all constructors
  1783. asCArray<int> funcs;
  1784. asSTypeBehaviour *beh = type.GetBehaviour();
  1785. if( beh )
  1786. {
  1787. if( type.GetObjectType()->flags & asOBJ_REF )
  1788. funcs = beh->factories;
  1789. else
  1790. funcs = beh->constructors;
  1791. }
  1792. asCString str = type.Format();
  1793. MatchFunctions(funcs, args, node, str.AddressOf());
  1794. if( funcs.GetLength() == 1 )
  1795. {
  1796. int r = asSUCCESS;
  1797. // Add the default values for arguments not explicitly supplied
  1798. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1799. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1800. r = CompileDefaultArgs(node, args, func);
  1801. if( r == asSUCCESS )
  1802. {
  1803. asSExprContext ctx(engine);
  1804. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  1805. {
  1806. if( isVarGlobOrMem == 0 )
  1807. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  1808. else
  1809. {
  1810. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  1811. ctx.bc.Instr(asBC_RDSPtr);
  1812. if( isVarGlobOrMem == 1 )
  1813. {
  1814. // Store the returned handle in the global variable
  1815. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1816. }
  1817. else
  1818. {
  1819. // Store the returned handle in the member
  1820. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1821. ctx.bc.Instr(asBC_RDSPtr);
  1822. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1823. }
  1824. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  1825. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1826. }
  1827. // Pop the reference left by the function call
  1828. ctx.bc.Instr(asBC_PopPtr);
  1829. }
  1830. else
  1831. {
  1832. bool onHeap = false;
  1833. if( isVarGlobOrMem == 0 )
  1834. {
  1835. // When the object is allocated on the heap, the address where the
  1836. // reference will be stored must be pushed on the stack before the
  1837. // arguments. This reference on the stack is safe, even if the script
  1838. // is suspended during the evaluation of the arguments.
  1839. onHeap = IsVariableOnHeap(offset);
  1840. if( onHeap )
  1841. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1842. }
  1843. else
  1844. {
  1845. // Push the address of the location where the variable will be stored on the stack.
  1846. // This reference is safe, because the addresses of the global variables cannot change.
  1847. onHeap = true;
  1848. if( isVarGlobOrMem == 1 )
  1849. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1850. else
  1851. {
  1852. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1853. ctx.bc.Instr(asBC_RDSPtr);
  1854. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1855. }
  1856. }
  1857. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1858. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1859. // When the object is allocated on the stack, the address to the
  1860. // object is pushed on the stack after the arguments as the object pointer
  1861. if( !onHeap )
  1862. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1863. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  1864. if( isVarGlobOrMem == 0 )
  1865. {
  1866. // Mark the object in the local variable as initialized
  1867. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  1868. }
  1869. }
  1870. bc->AddCode(&ctx.bc);
  1871. }
  1872. }
  1873. }
  1874. // Cleanup
  1875. for( asUINT n = 0; n < args.GetLength(); n++ )
  1876. if( args[n] )
  1877. {
  1878. asDELETE(args[n],asSExprContext);
  1879. }
  1880. }
  1881. }
  1882. else if( node && node->nodeType == snInitList )
  1883. {
  1884. asCTypeInfo ti;
  1885. ti.Set(type);
  1886. ti.isVariable = (isVarGlobOrMem == 0);
  1887. ti.isTemporary = false;
  1888. ti.stackOffset = (short)offset;
  1889. ti.isLValue = true;
  1890. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  1891. }
  1892. else if( node && node->nodeType == snAssignment )
  1893. {
  1894. asSExprContext ctx(engine);
  1895. // TODO: copy: Here we should look for the best matching constructor, instead of
  1896. // just the copy constructor. Only if no appropriate constructor is
  1897. // available should the assignment operator be used.
  1898. // Call the default constructor here
  1899. if( isVarGlobOrMem == 0 )
  1900. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  1901. else
  1902. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  1903. // Compile the expression
  1904. asSExprContext expr(engine);
  1905. int r = CompileAssignment(node, &expr);
  1906. if( r >= 0 )
  1907. {
  1908. if( type.IsPrimitive() )
  1909. {
  1910. if( type.IsReadOnly() && expr.type.isConstant )
  1911. {
  1912. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1913. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  1914. isConstantExpression = true;
  1915. *constantValue = expr.type.qwordValue;
  1916. }
  1917. asSExprContext lctx(engine);
  1918. if( isVarGlobOrMem == 0 )
  1919. lctx.type.SetVariable(type, offset, false);
  1920. else if( isVarGlobOrMem == 1 )
  1921. {
  1922. lctx.type.Set(type);
  1923. lctx.type.dataType.MakeReference(true);
  1924. // If it is an enum value, i.e. offset is negative, that is being compiled then
  1925. // we skip this as the bytecode won't be used anyway, only the constant value
  1926. if( offset >= 0 )
  1927. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  1928. }
  1929. else
  1930. {
  1931. asASSERT( isVarGlobOrMem == 2 );
  1932. lctx.type.Set(type);
  1933. lctx.type.dataType.MakeReference(true);
  1934. // Load the reference of the primitive member into the register
  1935. lctx.bc.InstrSHORT(asBC_PSF, 0);
  1936. lctx.bc.Instr(asBC_RDSPtr);
  1937. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1938. lctx.bc.Instr(asBC_PopRPtr);
  1939. }
  1940. lctx.type.dataType.MakeReadOnly(false);
  1941. lctx.type.isLValue = true;
  1942. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1943. ProcessDeferredParams(&ctx);
  1944. }
  1945. else
  1946. {
  1947. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  1948. // just the copy constructor. Only if no appropriate constructor is
  1949. // available should the assignment operator be used.
  1950. asSExprContext lexpr(engine);
  1951. lexpr.type.Set(type);
  1952. if( isVarGlobOrMem == 0 )
  1953. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  1954. else
  1955. lexpr.type.dataType.MakeReference(true);
  1956. // Allow initialization of constant variables
  1957. lexpr.type.dataType.MakeReadOnly(false);
  1958. if( type.IsObjectHandle() )
  1959. lexpr.type.isExplicitHandle = true;
  1960. if( isVarGlobOrMem == 0 )
  1961. {
  1962. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  1963. lexpr.type.stackOffset = (short)offset;
  1964. lexpr.type.isVariable = true;
  1965. }
  1966. else if( isVarGlobOrMem == 1 )
  1967. {
  1968. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1969. }
  1970. else
  1971. {
  1972. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  1973. lexpr.bc.Instr(asBC_RDSPtr);
  1974. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1975. lexpr.type.stackOffset = -1;
  1976. }
  1977. lexpr.type.isLValue = true;
  1978. // If left expression resolves into a registered type
  1979. // check if the assignment operator is overloaded, and check
  1980. // the type of the right hand expression. If none is found
  1981. // the default action is a direct copy if it is the same type
  1982. // and a simple assignment.
  1983. bool assigned = false;
  1984. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  1985. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1986. {
  1987. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1988. if( assigned )
  1989. {
  1990. // Pop the resulting value
  1991. if( !ctx.type.dataType.IsPrimitive() )
  1992. ctx.bc.Instr(asBC_PopPtr);
  1993. // Release the argument
  1994. ProcessDeferredParams(&ctx);
  1995. // Release temporary variable that may be allocated by the overloaded operator
  1996. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1997. }
  1998. }
  1999. if( !assigned )
  2000. {
  2001. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  2002. // If the expression is constant and the variable also is constant
  2003. // then mark the variable as pure constant. This will allow the compiler
  2004. // to optimize expressions with this variable.
  2005. if( type.IsReadOnly() && expr.type.isConstant )
  2006. {
  2007. isConstantExpression = true;
  2008. *constantValue = expr.type.qwordValue;
  2009. }
  2010. // Add expression code to bytecode
  2011. MergeExprBytecode(&ctx, &expr);
  2012. // Add byte code for storing value of expression in variable
  2013. ctx.bc.AddCode(&lexpr.bc);
  2014. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, errNode);
  2015. // Release temporary variables used by expression
  2016. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  2017. ctx.bc.Instr(asBC_PopPtr);
  2018. ProcessDeferredParams(&ctx);
  2019. }
  2020. }
  2021. }
  2022. bc->AddCode(&ctx.bc);
  2023. }
  2024. else
  2025. {
  2026. asASSERT( node == 0 );
  2027. // Call the default constructor here, as no explicit initialization is done
  2028. if( isVarGlobOrMem == 0 )
  2029. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2030. else
  2031. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2032. }
  2033. bc->OptimizeLocally(tempVariableOffsets);
  2034. return isConstantExpression;
  2035. }
  2036. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2037. {
  2038. // Check if the type supports initialization lists
  2039. if( var->dataType.GetObjectType() == 0 ||
  2040. var->dataType.GetBehaviour()->listFactory == 0 ||
  2041. var->dataType.IsObjectHandle() )
  2042. {
  2043. asCString str;
  2044. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  2045. Error(str, node);
  2046. return;
  2047. }
  2048. // Construct the buffer with the elements
  2049. // Find the list factory
  2050. int funcId = var->dataType.GetBehaviour()->listFactory;
  2051. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2052. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2053. // for small buffers so that the dynamic allocation is skipped
  2054. // Create a new special object type for the lists. Both asCRestore and the
  2055. // context exception handler will need this to know how to parse the buffer.
  2056. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2057. // Allocate a temporary variable to hold the pointer to the buffer
  2058. int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true);
  2059. asUINT bufferSize = 0;
  2060. // Evaluate all elements of the list
  2061. asSExprContext valueExpr(engine);
  2062. asCScriptNode *el = node;
  2063. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2064. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), bufferVar, bufferSize, valueExpr.bc);
  2065. asASSERT( r || patternNode == 0 );
  2066. UNUSED_VAR(r);
  2067. // After all values have been evaluated we know the final size of the buffer
  2068. asSExprContext allocExpr(engine);
  2069. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, bufferVar, bufferSize);
  2070. // Merge the bytecode into the final sequence
  2071. bc->AddCode(&allocExpr.bc);
  2072. bc->AddCode(&valueExpr.bc);
  2073. // The object itself is the last to be created and will receive the pointer to the buffer
  2074. asCArray<asSExprContext *> args;
  2075. asSExprContext arg1(engine);
  2076. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2077. arg1.type.dataType.MakeReference(true);
  2078. arg1.bc.InstrSHORT(asBC_PshVPtr, bufferVar);
  2079. args.PushLast(&arg1);
  2080. asSExprContext ctx(engine);
  2081. if( var->isVariable )
  2082. {
  2083. asASSERT( isVarGlobOrMem == 0 );
  2084. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2085. {
  2086. ctx.bc.AddCode(&arg1.bc);
  2087. // Call factory and store the handle in the given variable
  2088. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2089. ctx.bc.Instr(asBC_PopPtr);
  2090. }
  2091. else
  2092. {
  2093. // Call the constructor
  2094. // When the object is allocated on the heap, the address where the
  2095. // reference will be stored must be pushed on the stack before the
  2096. // arguments. This reference on the stack is safe, even if the script
  2097. // is suspended during the evaluation of the arguments.
  2098. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2099. if( onHeap )
  2100. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2101. ctx.bc.AddCode(&arg1.bc);
  2102. // When the object is allocated on the stack, the address to the
  2103. // object is pushed on the stack after the arguments as the object pointer
  2104. if( !onHeap )
  2105. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2106. PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
  2107. // Mark the object in the local variable as initialized
  2108. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2109. }
  2110. }
  2111. else
  2112. {
  2113. if( var->dataType.GetObjectType()->GetFlags() & asOBJ_REF )
  2114. {
  2115. ctx.bc.AddCode(&arg1.bc);
  2116. PerformFunctionCall(funcId, &ctx, false, &args);
  2117. ctx.bc.Instr(asBC_RDSPtr);
  2118. if( isVarGlobOrMem == 1 )
  2119. {
  2120. // Store the returned handle in the global variable
  2121. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2122. }
  2123. else
  2124. {
  2125. // Store the returned handle in the member
  2126. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2127. ctx.bc.Instr(asBC_RDSPtr);
  2128. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2129. }
  2130. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  2131. ctx.bc.Instr(asBC_PopPtr);
  2132. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2133. }
  2134. else
  2135. {
  2136. // Put the address where the object pointer will be placed on the stack
  2137. if( isVarGlobOrMem == 1 )
  2138. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2139. else
  2140. {
  2141. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2142. ctx.bc.Instr(asBC_RDSPtr);
  2143. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2144. }
  2145. // Add the address of the list buffer as the argument
  2146. ctx.bc.AddCode(&arg1.bc);
  2147. // Call the ALLOC instruction to allocate memory and invoke constructor
  2148. PerformFunctionCall(funcId, &ctx, true, &args, var->dataType.GetObjectType());
  2149. }
  2150. }
  2151. bc->AddCode(&ctx.bc);
  2152. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2153. // each element in the buffer so there is no need to do this manually
  2154. bc->InstrW_PTR(asBC_FREE, bufferVar, listPatternType);
  2155. ReleaseTemporaryVariable(bufferVar, bc);
  2156. }
  2157. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode)
  2158. {
  2159. if( patternNode->type == asLPT_START )
  2160. {
  2161. if( valueNode->nodeType != snInitList )
  2162. {
  2163. Error(TXT_EXPECTED_LIST, valueNode);
  2164. return -1;
  2165. }
  2166. // Compile all values until asLPT_END
  2167. patternNode = patternNode->next;
  2168. asCScriptNode *node = valueNode->firstChild;
  2169. while( patternNode->type != asLPT_END )
  2170. {
  2171. if( node == 0 )
  2172. {
  2173. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  2174. return -1;
  2175. }
  2176. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode);
  2177. if( r < 0 ) return r;
  2178. asASSERT( patternNode );
  2179. }
  2180. if( node )
  2181. {
  2182. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  2183. return -1;
  2184. }
  2185. // Move to the next node
  2186. valueNode = valueNode->next;
  2187. patternNode = patternNode->next;
  2188. }
  2189. else if( patternNode->type == asLPT_REPEAT )
  2190. {
  2191. // The following values will be repeated N times
  2192. patternNode = patternNode->next;
  2193. // Keep track of the patternNode so it can be reset
  2194. asSListPatternNode *nextNode = patternNode;
  2195. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  2196. if( bufferSize & 0x3 )
  2197. bufferSize += 4 - (bufferSize & 0x3);
  2198. // The first dword will hold the number of elements in the list
  2199. asDWORD currSize = bufferSize;
  2200. bufferSize += 4;
  2201. asUINT countElements = 0;
  2202. asSExprContext ctx(engine);
  2203. while( valueNode )
  2204. {
  2205. patternNode = nextNode;
  2206. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc);
  2207. if( r < 0 ) return r;
  2208. countElements++;
  2209. }
  2210. // The first dword in the buffer will hold the number of elements
  2211. byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  2212. // Add the values
  2213. byteCode.AddCode(&ctx.bc);
  2214. }
  2215. else if( patternNode->type == asLPT_TYPE )
  2216. {
  2217. // Determine the size of the element
  2218. asUINT size = 0;
  2219. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  2220. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  2221. {
  2222. asSExprContext lctx(engine);
  2223. asSExprContext rctx(engine);
  2224. if( valueNode->nodeType == snAssignment )
  2225. {
  2226. // Compile the assignment expression
  2227. CompileAssignment(valueNode, &rctx);
  2228. if( dt.GetTokenType() == ttQuestion )
  2229. {
  2230. // We now know the type
  2231. dt = rctx.type.dataType;
  2232. dt.MakeReadOnly(false);
  2233. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2234. if( bufferSize & 0x3 )
  2235. bufferSize += 4 - (bufferSize & 0x3);
  2236. // Place the type id in the buffer
  2237. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  2238. bufferSize += 4;
  2239. }
  2240. }
  2241. else if( valueNode->nodeType == snInitList )
  2242. {
  2243. if( dt.GetTokenType() == ttQuestion )
  2244. {
  2245. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  2246. asCString str;
  2247. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  2248. Error(str.AddressOf(), valueNode);
  2249. rctx.type.SetDummy();
  2250. dt = rctx.type.dataType;
  2251. }
  2252. else
  2253. {
  2254. // Allocate a temporary variable that will be initialized with the list
  2255. int offset = AllocateVariable(dt, true);
  2256. rctx.type.Set(dt);
  2257. rctx.type.isVariable = true;
  2258. rctx.type.isTemporary = true;
  2259. rctx.type.stackOffset = (short)offset;
  2260. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  2261. // Put the object on the stack
  2262. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  2263. // It is a reference that we place on the stack
  2264. rctx.type.dataType.MakeReference(true);
  2265. }
  2266. }
  2267. // Determine size of the element
  2268. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2269. size = dt.GetSizeInMemoryBytes();
  2270. else
  2271. size = AS_PTR_SIZE*4;
  2272. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2273. if( size >= 4 && (bufferSize & 0x3) )
  2274. bufferSize += 4 - (bufferSize & 0x3);
  2275. // Compile the lvalue
  2276. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2277. lctx.type.Set(dt);
  2278. lctx.type.isLValue = true;
  2279. if( dt.IsPrimitive() )
  2280. {
  2281. lctx.bc.Instr(asBC_PopRPtr);
  2282. lctx.type.dataType.MakeReference(true);
  2283. }
  2284. else if( dt.IsObjectHandle() ||
  2285. dt.GetObjectType()->flags & asOBJ_REF )
  2286. {
  2287. lctx.type.isExplicitHandle = true;
  2288. lctx.type.dataType.MakeReference(true);
  2289. }
  2290. else
  2291. {
  2292. asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE );
  2293. // Make sure the object has been constructed before the assignment
  2294. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  2295. asSTypeBehaviour *beh = dt.GetBehaviour();
  2296. int func = 0;
  2297. if( beh ) func = beh->construct;
  2298. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2299. {
  2300. asCString str;
  2301. // TODO: funcdef: asCDataType should have a GetTypeName()
  2302. if( dt.GetFuncDef() )
  2303. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2304. else
  2305. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2306. Error(str, valueNode);
  2307. }
  2308. else if( func )
  2309. {
  2310. // Call the constructor as a normal function
  2311. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2312. asSExprContext ctx(engine);
  2313. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  2314. byteCode.AddCode(&ctx.bc);
  2315. }
  2316. }
  2317. asSExprContext ctx(engine);
  2318. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  2319. if( !lctx.type.dataType.IsPrimitive() )
  2320. ctx.bc.Instr(asBC_PopPtr);
  2321. // Release temporary variables used by expression
  2322. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2323. ProcessDeferredParams(&ctx);
  2324. byteCode.AddCode(&ctx.bc);
  2325. }
  2326. else
  2327. {
  2328. // There is no specific value so we need to fill it with a default value
  2329. if( dt.GetTokenType() == ttQuestion )
  2330. {
  2331. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2332. if( bufferSize & 0x3 )
  2333. bufferSize += 4 - (bufferSize & 0x3);
  2334. // Place the type id for a null handle in the buffer
  2335. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  2336. bufferSize += 4;
  2337. dt = asCDataType::CreateNullHandle();
  2338. // No need to initialize the handle as the buffer is already initialized with zeroes
  2339. }
  2340. else if( dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_VALUE )
  2341. {
  2342. // For value types with default constructor we need to call the constructor
  2343. asSTypeBehaviour *beh = dt.GetBehaviour();
  2344. int func = 0;
  2345. if( beh ) func = beh->construct;
  2346. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2347. {
  2348. asCString str;
  2349. // TODO: funcdef: asCDataType should have a GetTypeName()
  2350. if( dt.GetFuncDef() )
  2351. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2352. else
  2353. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2354. Error(str, valueNode);
  2355. }
  2356. else if( func )
  2357. {
  2358. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2359. if( bufferSize & 0x3 )
  2360. bufferSize += 4 - (bufferSize & 0x3);
  2361. // Call the constructor as a normal function
  2362. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2363. asSExprContext ctx(engine);
  2364. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  2365. byteCode.AddCode(&ctx.bc);
  2366. }
  2367. }
  2368. else if( !dt.IsObjectHandle() && dt.GetObjectType() && dt.GetObjectType()->flags & asOBJ_REF )
  2369. {
  2370. // For ref types (not handles) we need to call the default factory
  2371. asSTypeBehaviour *beh = dt.GetBehaviour();
  2372. int func = 0;
  2373. if( beh ) func = beh->factory;
  2374. if( func == 0 )
  2375. {
  2376. asCString str;
  2377. // TODO: funcdef: asCDataType should have a GetTypeName()
  2378. if( dt.GetFuncDef() )
  2379. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2380. else
  2381. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2382. Error(str, valueNode);
  2383. }
  2384. else if( func )
  2385. {
  2386. asSExprContext rctx(engine);
  2387. PerformFunctionCall(func, &rctx, false, 0, dt.GetObjectType());
  2388. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  2389. if( bufferSize & 0x3 )
  2390. bufferSize += 4 - (bufferSize & 0x3);
  2391. asSExprContext lctx(engine);
  2392. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2393. lctx.type.Set(dt);
  2394. lctx.type.isLValue = true;
  2395. lctx.type.isExplicitHandle = true;
  2396. lctx.type.dataType.MakeReference(true);
  2397. asSExprContext ctx(engine);
  2398. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  2399. if( !lctx.type.dataType.IsPrimitive() )
  2400. ctx.bc.Instr(asBC_PopPtr);
  2401. // Release temporary variables used by expression
  2402. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2403. ProcessDeferredParams(&ctx);
  2404. byteCode.AddCode(&ctx.bc);
  2405. }
  2406. }
  2407. }
  2408. // Determine size of the element
  2409. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2410. size = dt.GetSizeInMemoryBytes();
  2411. else
  2412. size = AS_PTR_SIZE*4;
  2413. asASSERT( size <= 4 || (size & 0x3) == 0 );
  2414. // Move to the next element
  2415. bufferSize += size;
  2416. patternNode = patternNode->next;
  2417. valueNode = valueNode->next;
  2418. }
  2419. else
  2420. asASSERT( false );
  2421. return 0;
  2422. }
  2423. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  2424. {
  2425. // Don't clear the hasReturn flag if this is an empty statement
  2426. // to avoid false errors of 'not all paths return'
  2427. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  2428. *hasReturn = false;
  2429. if( statement->nodeType == snStatementBlock )
  2430. CompileStatementBlock(statement, true, hasReturn, bc);
  2431. else if( statement->nodeType == snIf )
  2432. CompileIfStatement(statement, hasReturn, bc);
  2433. else if( statement->nodeType == snFor )
  2434. CompileForStatement(statement, bc);
  2435. else if( statement->nodeType == snWhile )
  2436. CompileWhileStatement(statement, bc);
  2437. else if( statement->nodeType == snDoWhile )
  2438. CompileDoWhileStatement(statement, bc);
  2439. else if( statement->nodeType == snExpressionStatement )
  2440. CompileExpressionStatement(statement, bc);
  2441. else if( statement->nodeType == snBreak )
  2442. CompileBreakStatement(statement, bc);
  2443. else if( statement->nodeType == snContinue )
  2444. CompileContinueStatement(statement, bc);
  2445. else if( statement->nodeType == snSwitch )
  2446. CompileSwitchStatement(statement, hasReturn, bc);
  2447. else if( statement->nodeType == snReturn )
  2448. {
  2449. CompileReturnStatement(statement, bc);
  2450. *hasReturn = true;
  2451. }
  2452. }
  2453. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  2454. {
  2455. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  2456. // Reserve label for break statements
  2457. int breakLabel = nextLabel++;
  2458. breakLabels.PushLast(breakLabel);
  2459. // Add a variable scope that will be used by CompileBreak
  2460. // to know where to stop deallocating variables
  2461. AddVariableScope(true, false);
  2462. //---------------------------
  2463. // Compile the switch expression
  2464. //-------------------------------
  2465. // Compile the switch expression
  2466. asSExprContext expr(engine);
  2467. CompileAssignment(snode->firstChild, &expr);
  2468. // Verify that the expression is a primitive type
  2469. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  2470. {
  2471. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  2472. return;
  2473. }
  2474. ProcessPropertyGetAccessor(&expr, snode);
  2475. // TODO: Need to support 64bit integers
  2476. // Convert the expression to a 32bit variable
  2477. asCDataType to;
  2478. if( expr.type.dataType.IsIntegerType() )
  2479. to.SetTokenType(ttInt);
  2480. else if( expr.type.dataType.IsUnsignedType() )
  2481. to.SetTokenType(ttUInt);
  2482. // Make sure the value is in a variable
  2483. if( expr.type.dataType.IsReference() )
  2484. ConvertToVariable(&expr);
  2485. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  2486. ConvertToVariable(&expr);
  2487. int offset = expr.type.stackOffset;
  2488. ProcessDeferredParams(&expr);
  2489. //-------------------------------
  2490. // Determine case values and labels
  2491. //--------------------------------
  2492. // Remember the first label so that we can later pass the
  2493. // correct label to each CompileCase()
  2494. int firstCaseLabel = nextLabel;
  2495. int defaultLabel = 0;
  2496. asCArray<int> caseValues;
  2497. asCArray<int> caseLabels;
  2498. // Compile all case comparisons and make them jump to the right label
  2499. asCScriptNode *cnode = snode->firstChild->next;
  2500. while( cnode )
  2501. {
  2502. // Each case should have a constant expression
  2503. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2504. {
  2505. // Compile expression
  2506. asSExprContext c(engine);
  2507. CompileExpression(cnode->firstChild, &c);
  2508. // Verify that the result is a constant
  2509. if( !c.type.isConstant )
  2510. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  2511. // Verify that the result is an integral number
  2512. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
  2513. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  2514. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  2515. // Has this case been declared already?
  2516. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  2517. {
  2518. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  2519. }
  2520. // TODO: Optimize: We can insert the numbers sorted already
  2521. // Store constant for later use
  2522. caseValues.PushLast(c.type.intValue);
  2523. // Reserve label for this case
  2524. caseLabels.PushLast(nextLabel++);
  2525. }
  2526. else
  2527. {
  2528. // TODO: It shouldn't be necessary for the default case to be the last one.
  2529. // Is default the last case?
  2530. if( cnode->next )
  2531. {
  2532. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  2533. break;
  2534. }
  2535. // Reserve label for this case
  2536. defaultLabel = nextLabel++;
  2537. }
  2538. cnode = cnode->next;
  2539. }
  2540. // check for empty switch
  2541. if (caseValues.GetLength() == 0)
  2542. {
  2543. Error(TXT_EMPTY_SWITCH, snode);
  2544. return;
  2545. }
  2546. if( defaultLabel == 0 )
  2547. defaultLabel = breakLabel;
  2548. //---------------------------------
  2549. // Output the optimized case comparisons
  2550. // with jumps to the case code
  2551. //------------------------------------
  2552. // Sort the case values by increasing value. Do the sort together with the labels
  2553. // A simple bubble sort is sufficient since we don't expect a huge number of values
  2554. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  2555. {
  2556. for( int bck = fwd - 1; bck >= 0; bck-- )
  2557. {
  2558. int bckp = bck + 1;
  2559. if( caseValues[bck] > caseValues[bckp] )
  2560. {
  2561. // Swap the values in both arrays
  2562. int swap = caseValues[bckp];
  2563. caseValues[bckp] = caseValues[bck];
  2564. caseValues[bck] = swap;
  2565. swap = caseLabels[bckp];
  2566. caseLabels[bckp] = caseLabels[bck];
  2567. caseLabels[bck] = swap;
  2568. }
  2569. else
  2570. break;
  2571. }
  2572. }
  2573. // Find ranges of consecutive numbers
  2574. asCArray<int> ranges;
  2575. ranges.PushLast(0);
  2576. asUINT n;
  2577. for( n = 1; n < caseValues.GetLength(); ++n )
  2578. {
  2579. // We can join numbers that are less than 5 numbers
  2580. // apart since the output code will still be smaller
  2581. if( caseValues[n] > caseValues[n-1] + 5 )
  2582. ranges.PushLast(n);
  2583. }
  2584. // If the value is larger than the largest case value, jump to default
  2585. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2586. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  2587. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2588. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  2589. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2590. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  2591. // binary search instead of a linear search through the ranges
  2592. // For each range
  2593. int range;
  2594. for( range = 0; range < (int)ranges.GetLength(); range++ )
  2595. {
  2596. // Find the largest value in this range
  2597. int maxRange = caseValues[ranges[range]];
  2598. int index = ranges[range];
  2599. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  2600. maxRange = caseValues[index];
  2601. // If there are only 2 numbers then it is better to compare them directly
  2602. if( index - ranges[range] > 2 )
  2603. {
  2604. // If the value is smaller than the smallest case value in the range, jump to default
  2605. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2606. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2607. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2608. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  2609. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2610. int nextRangeLabel = nextLabel++;
  2611. // If this is the last range we don't have to make this test
  2612. if( range < (int)ranges.GetLength() - 1 )
  2613. {
  2614. // If the value is larger than the largest case value in the range, jump to the next range
  2615. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2616. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  2617. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2618. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  2619. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2620. }
  2621. // Jump forward according to the value
  2622. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2623. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2624. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  2625. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2626. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  2627. // Add the list of jumps to the correct labels (any holes, jump to default)
  2628. index = ranges[range];
  2629. for( int n = caseValues[index]; n <= maxRange; n++ )
  2630. {
  2631. if( caseValues[index] == n )
  2632. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  2633. else
  2634. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2635. }
  2636. expr.bc.Label((short)nextRangeLabel);
  2637. }
  2638. else
  2639. {
  2640. // Simply make a comparison with each value
  2641. int n;
  2642. for( n = ranges[range]; n < index; ++n )
  2643. {
  2644. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2645. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  2646. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2647. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2648. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2649. }
  2650. }
  2651. }
  2652. // Catch any value that falls trough
  2653. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2654. // Release the temporary variable previously stored
  2655. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2656. // TODO: optimize: Should optimize each piece individually
  2657. expr.bc.OptimizeLocally(tempVariableOffsets);
  2658. //----------------------------------
  2659. // Output case implementations
  2660. //----------------------------------
  2661. // Compile case implementations, each one with the label before it
  2662. cnode = snode->firstChild->next;
  2663. while( cnode )
  2664. {
  2665. // Each case should have a constant expression
  2666. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2667. {
  2668. expr.bc.Label((short)firstCaseLabel++);
  2669. CompileCase(cnode->firstChild->next, &expr.bc);
  2670. }
  2671. else
  2672. {
  2673. expr.bc.Label((short)defaultLabel);
  2674. // Is default the last case?
  2675. if( cnode->next )
  2676. {
  2677. // We've already reported this error
  2678. break;
  2679. }
  2680. CompileCase(cnode->firstChild, &expr.bc);
  2681. }
  2682. cnode = cnode->next;
  2683. }
  2684. //--------------------------------
  2685. bc->AddCode(&expr.bc);
  2686. // Add break label
  2687. bc->Label((short)breakLabel);
  2688. breakLabels.PopLast();
  2689. RemoveVariableScope();
  2690. }
  2691. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2692. {
  2693. bool isFinished = false;
  2694. bool hasReturn = false;
  2695. bool hasUnreachableCode = false;
  2696. while( node )
  2697. {
  2698. if( !hasUnreachableCode && (hasReturn || isFinished) )
  2699. {
  2700. hasUnreachableCode = true;
  2701. Warning(TXT_UNREACHABLE_CODE, node);
  2702. break;
  2703. }
  2704. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2705. isFinished = true;
  2706. asCByteCode statement(engine);
  2707. if( node->nodeType == snDeclaration )
  2708. {
  2709. Error(TXT_DECL_IN_SWITCH, node);
  2710. // Compile it anyway to avoid further compiler errors
  2711. CompileDeclaration(node, &statement);
  2712. }
  2713. else
  2714. CompileStatement(node, &hasReturn, &statement);
  2715. LineInstr(bc, node->tokenPos);
  2716. bc->AddCode(&statement);
  2717. if( !hasCompileErrors )
  2718. asASSERT( tempVariables.GetLength() == 0 );
  2719. node = node->next;
  2720. }
  2721. }
  2722. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2723. {
  2724. // We will use one label for the if statement
  2725. // and possibly another for the else statement
  2726. int afterLabel = nextLabel++;
  2727. // Compile the expression
  2728. asSExprContext expr(engine);
  2729. CompileAssignment(inode->firstChild, &expr);
  2730. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2731. {
  2732. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2733. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2734. }
  2735. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2736. ProcessDeferredParams(&expr);
  2737. if( !expr.type.isConstant )
  2738. {
  2739. ProcessPropertyGetAccessor(&expr, inode);
  2740. ConvertToVariable(&expr);
  2741. // Add a test
  2742. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2743. expr.bc.Instr(asBC_ClrHi);
  2744. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2745. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2746. expr.bc.OptimizeLocally(tempVariableOffsets);
  2747. bc->AddCode(&expr.bc);
  2748. }
  2749. else if( expr.type.dwordValue == 0 )
  2750. {
  2751. // Jump to the else case
  2752. bc->InstrINT(asBC_JMP, afterLabel);
  2753. // TODO: Should we warn that the expression will always go to the else?
  2754. }
  2755. // Compile the if statement
  2756. bool origIsConstructorCalled = m_isConstructorCalled;
  2757. bool hasReturn1;
  2758. asCByteCode ifBC(engine);
  2759. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2760. // Add the byte code
  2761. LineInstr(bc, inode->firstChild->next->tokenPos);
  2762. bc->AddCode(&ifBC);
  2763. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2764. {
  2765. // Don't allow if( expr );
  2766. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2767. }
  2768. // If one of the statements call the constructor, the other must as well
  2769. // otherwise it is possible the constructor is never called
  2770. bool constructorCall1 = false;
  2771. bool constructorCall2 = false;
  2772. if( !origIsConstructorCalled && m_isConstructorCalled )
  2773. constructorCall1 = true;
  2774. // Do we have an else statement?
  2775. if( inode->firstChild->next != inode->lastChild )
  2776. {
  2777. // Reset the constructor called flag so the else statement can call the constructor too
  2778. m_isConstructorCalled = origIsConstructorCalled;
  2779. int afterElse = 0;
  2780. if( !hasReturn1 )
  2781. {
  2782. afterElse = nextLabel++;
  2783. // Add jump to after the else statement
  2784. bc->InstrINT(asBC_JMP, afterElse);
  2785. }
  2786. // Add label for the else statement
  2787. bc->Label((short)afterLabel);
  2788. bool hasReturn2;
  2789. asCByteCode elseBC(engine);
  2790. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2791. // Add byte code for the else statement
  2792. LineInstr(bc, inode->lastChild->tokenPos);
  2793. bc->AddCode(&elseBC);
  2794. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2795. {
  2796. // Don't allow if( expr ) {} else;
  2797. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2798. }
  2799. if( !hasReturn1 )
  2800. {
  2801. // Add label for the end of else statement
  2802. bc->Label((short)afterElse);
  2803. }
  2804. // The if statement only has return if both alternatives have
  2805. *hasReturn = hasReturn1 && hasReturn2;
  2806. if( !origIsConstructorCalled && m_isConstructorCalled )
  2807. constructorCall2 = true;
  2808. }
  2809. else
  2810. {
  2811. // Add label for the end of if statement
  2812. bc->Label((short)afterLabel);
  2813. *hasReturn = false;
  2814. }
  2815. // Make sure both or neither conditions call a constructor
  2816. if( (constructorCall1 && !constructorCall2) ||
  2817. (constructorCall2 && !constructorCall1) )
  2818. {
  2819. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2820. }
  2821. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2822. }
  2823. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2824. {
  2825. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2826. AddVariableScope(true, true);
  2827. // We will use three labels for the for loop
  2828. int conditionLabel = nextLabel++;
  2829. int afterLabel = nextLabel++;
  2830. int continueLabel = nextLabel++;
  2831. int insideLabel = nextLabel++;
  2832. continueLabels.PushLast(continueLabel);
  2833. breakLabels.PushLast(afterLabel);
  2834. //---------------------------------------
  2835. // Compile the initialization statement
  2836. asCByteCode initBC(engine);
  2837. LineInstr(&initBC, fnode->firstChild->tokenPos);
  2838. if( fnode->firstChild->nodeType == snDeclaration )
  2839. CompileDeclaration(fnode->firstChild, &initBC);
  2840. else
  2841. CompileExpressionStatement(fnode->firstChild, &initBC);
  2842. //-----------------------------------
  2843. // Compile the condition statement
  2844. asSExprContext expr(engine);
  2845. asCScriptNode *second = fnode->firstChild->next;
  2846. if( second->firstChild )
  2847. {
  2848. int r = CompileAssignment(second->firstChild, &expr);
  2849. if( r >= 0 )
  2850. {
  2851. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2852. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2853. else
  2854. {
  2855. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2856. ProcessDeferredParams(&expr);
  2857. ProcessPropertyGetAccessor(&expr, second);
  2858. // If expression is false exit the loop
  2859. ConvertToVariable(&expr);
  2860. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2861. expr.bc.Instr(asBC_ClrHi);
  2862. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  2863. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2864. expr.bc.OptimizeLocally(tempVariableOffsets);
  2865. // Prepend the line instruction for the condition
  2866. asCByteCode tmp(engine);
  2867. LineInstr(&tmp, second->firstChild->tokenPos);
  2868. tmp.AddCode(&expr.bc);
  2869. expr.bc.AddCode(&tmp);
  2870. }
  2871. }
  2872. }
  2873. //---------------------------
  2874. // Compile the increment statement
  2875. asCByteCode nextBC(engine);
  2876. asCScriptNode *third = second->next;
  2877. if( third->nodeType == snExpressionStatement )
  2878. {
  2879. LineInstr(&nextBC, third->tokenPos);
  2880. CompileExpressionStatement(third, &nextBC);
  2881. }
  2882. //------------------------------
  2883. // Compile loop statement
  2884. bool hasReturn;
  2885. asCByteCode forBC(engine);
  2886. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2887. //-------------------------------
  2888. // Join the code pieces
  2889. bc->AddCode(&initBC);
  2890. bc->InstrDWORD(asBC_JMP, conditionLabel);
  2891. bc->Label((short)insideLabel);
  2892. // Add a suspend bytecode inside the loop to guarantee
  2893. // that the application can suspend the execution
  2894. bc->Instr(asBC_SUSPEND);
  2895. bc->InstrPTR(asBC_JitEntry, 0);
  2896. LineInstr(bc, fnode->lastChild->tokenPos);
  2897. bc->AddCode(&forBC);
  2898. bc->Label((short)continueLabel);
  2899. bc->AddCode(&nextBC);
  2900. bc->Label((short)conditionLabel);
  2901. if( expr.bc.GetLastInstr() == -1 )
  2902. // There is no condition, so we just always jump
  2903. bc->InstrDWORD(asBC_JMP, insideLabel);
  2904. else
  2905. bc->AddCode(&expr.bc);
  2906. bc->Label((short)afterLabel);
  2907. continueLabels.PopLast();
  2908. breakLabels.PopLast();
  2909. // Deallocate variables in this block, in reverse order
  2910. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2911. {
  2912. sVariable *v = variables->variables[n];
  2913. // Call variable destructors here, for variables not yet destroyed
  2914. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2915. // Don't deallocate function parameters
  2916. if( v->stackOffset > 0 )
  2917. DeallocateVariable(v->stackOffset);
  2918. }
  2919. RemoveVariableScope();
  2920. }
  2921. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2922. {
  2923. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2924. AddVariableScope(true, true);
  2925. // We will use two labels for the while loop
  2926. int beforeLabel = nextLabel++;
  2927. int afterLabel = nextLabel++;
  2928. continueLabels.PushLast(beforeLabel);
  2929. breakLabels.PushLast(afterLabel);
  2930. // Add label before the expression
  2931. bc->Label((short)beforeLabel);
  2932. // Compile expression
  2933. asSExprContext expr(engine);
  2934. CompileAssignment(wnode->firstChild, &expr);
  2935. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2936. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2937. else
  2938. {
  2939. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2940. ProcessDeferredParams(&expr);
  2941. ProcessPropertyGetAccessor(&expr, wnode);
  2942. // Add byte code for the expression
  2943. ConvertToVariable(&expr);
  2944. // Jump to end of statement if expression is false
  2945. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2946. expr.bc.Instr(asBC_ClrHi);
  2947. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2948. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2949. expr.bc.OptimizeLocally(tempVariableOffsets);
  2950. bc->AddCode(&expr.bc);
  2951. }
  2952. // Add a suspend bytecode inside the loop to guarantee
  2953. // that the application can suspend the execution
  2954. bc->Instr(asBC_SUSPEND);
  2955. bc->InstrPTR(asBC_JitEntry, 0);
  2956. // Compile statement
  2957. bool hasReturn;
  2958. asCByteCode whileBC(engine);
  2959. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2960. // Add byte code for the statement
  2961. LineInstr(bc, wnode->lastChild->tokenPos);
  2962. bc->AddCode(&whileBC);
  2963. // Jump to the expression
  2964. bc->InstrINT(asBC_JMP, beforeLabel);
  2965. // Add label after the statement
  2966. bc->Label((short)afterLabel);
  2967. continueLabels.PopLast();
  2968. breakLabels.PopLast();
  2969. RemoveVariableScope();
  2970. }
  2971. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2972. {
  2973. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2974. AddVariableScope(true, true);
  2975. // We will use two labels for the while loop
  2976. int beforeLabel = nextLabel++;
  2977. int beforeTest = nextLabel++;
  2978. int afterLabel = nextLabel++;
  2979. continueLabels.PushLast(beforeTest);
  2980. breakLabels.PushLast(afterLabel);
  2981. // Add label before the statement
  2982. bc->Label((short)beforeLabel);
  2983. // Compile statement
  2984. bool hasReturn;
  2985. asCByteCode whileBC(engine);
  2986. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2987. // Add byte code for the statement
  2988. LineInstr(bc, wnode->firstChild->tokenPos);
  2989. bc->AddCode(&whileBC);
  2990. // Add label before the expression
  2991. bc->Label((short)beforeTest);
  2992. // Add a suspend bytecode inside the loop to guarantee
  2993. // that the application can suspend the execution
  2994. bc->Instr(asBC_SUSPEND);
  2995. bc->InstrPTR(asBC_JitEntry, 0);
  2996. // Add a line instruction
  2997. LineInstr(bc, wnode->lastChild->tokenPos);
  2998. // Compile expression
  2999. asSExprContext expr(engine);
  3000. CompileAssignment(wnode->lastChild, &expr);
  3001. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3002. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3003. else
  3004. {
  3005. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3006. ProcessDeferredParams(&expr);
  3007. ProcessPropertyGetAccessor(&expr, wnode);
  3008. // Add byte code for the expression
  3009. ConvertToVariable(&expr);
  3010. // Jump to next iteration if expression is true
  3011. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3012. expr.bc.Instr(asBC_ClrHi);
  3013. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3014. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3015. expr.bc.OptimizeLocally(tempVariableOffsets);
  3016. bc->AddCode(&expr.bc);
  3017. }
  3018. // Add label after the statement
  3019. bc->Label((short)afterLabel);
  3020. continueLabels.PopLast();
  3021. breakLabels.PopLast();
  3022. RemoveVariableScope();
  3023. }
  3024. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3025. {
  3026. if( breakLabels.GetLength() == 0 )
  3027. {
  3028. Error(TXT_INVALID_BREAK, node);
  3029. return;
  3030. }
  3031. // Add destructor calls for all variables that will go out of scope
  3032. // Put this clean up in a block to allow exception handler to understand them
  3033. bc->Block(true);
  3034. asCVariableScope *vs = variables;
  3035. while( !vs->isBreakScope )
  3036. {
  3037. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3038. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3039. vs = vs->parent;
  3040. }
  3041. bc->Block(false);
  3042. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  3043. }
  3044. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  3045. {
  3046. if( continueLabels.GetLength() == 0 )
  3047. {
  3048. Error(TXT_INVALID_CONTINUE, node);
  3049. return;
  3050. }
  3051. // Add destructor calls for all variables that will go out of scope
  3052. // Put this clean up in a block to allow exception handler to understand them
  3053. bc->Block(true);
  3054. asCVariableScope *vs = variables;
  3055. while( !vs->isContinueScope )
  3056. {
  3057. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3058. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3059. vs = vs->parent;
  3060. }
  3061. bc->Block(false);
  3062. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  3063. }
  3064. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  3065. {
  3066. if( enode->firstChild )
  3067. {
  3068. // Compile the expression
  3069. asSExprContext expr(engine);
  3070. CompileAssignment(enode->firstChild, &expr);
  3071. // If we get here and there is still an unprocessed property
  3072. // accessor, then process it as a get access. Don't call if there is
  3073. // already a compile error, or we might report an error that is not valid
  3074. if( !hasCompileErrors )
  3075. ProcessPropertyGetAccessor(&expr, enode);
  3076. // Pop the value from the stack
  3077. if( !expr.type.dataType.IsPrimitive() )
  3078. expr.bc.Instr(asBC_PopPtr);
  3079. // Release temporary variables used by expression
  3080. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3081. ProcessDeferredParams(&expr);
  3082. expr.bc.OptimizeLocally(tempVariableOffsets);
  3083. bc->AddCode(&expr.bc);
  3084. }
  3085. }
  3086. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  3087. {
  3088. // If the object already is stored in temporary variable then nothing needs to be done
  3089. // Note, a type can be temporary without being a variable, in which case it is holding off
  3090. // on releasing a previously used object.
  3091. if( ctx->type.isTemporary && ctx->type.isVariable &&
  3092. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  3093. {
  3094. // If the temporary object is currently not a reference
  3095. // the expression needs to be reevaluated to a reference
  3096. if( !ctx->type.dataType.IsReference() )
  3097. {
  3098. ctx->bc.Instr(asBC_PopPtr);
  3099. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3100. ctx->type.dataType.MakeReference(true);
  3101. }
  3102. return;
  3103. }
  3104. // Allocate temporary variable
  3105. asCDataType dt = ctx->type.dataType;
  3106. dt.MakeReference(false);
  3107. dt.MakeReadOnly(false);
  3108. int offset = AllocateVariable(dt, true, forceOnHeap);
  3109. // Objects stored on the stack are not considered references
  3110. dt.MakeReference(IsVariableOnHeap(offset));
  3111. asCTypeInfo lvalue;
  3112. lvalue.Set(dt);
  3113. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  3114. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3115. if( !dt.IsObjectHandle() &&
  3116. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  3117. {
  3118. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  3119. // Use the copy constructor/factory when available
  3120. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  3121. }
  3122. else
  3123. {
  3124. // Allocate and construct the temporary object
  3125. int r = CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  3126. if( r < 0 )
  3127. {
  3128. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  3129. }
  3130. else
  3131. {
  3132. // Assign the object to the temporary variable
  3133. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  3134. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3135. r = PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  3136. if( r < 0 )
  3137. {
  3138. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  3139. }
  3140. // Release any temp that may have been created as the result of opAssign
  3141. ReleaseTemporaryVariable(lvalue, &ctx->bc);
  3142. // Pop the original reference
  3143. if( !lvalue.dataType.IsPrimitive() )
  3144. ctx->bc.Instr(asBC_PopPtr);
  3145. }
  3146. // If the expression was holding off on releasing a
  3147. // previously used object, we need to release it now
  3148. if( ctx->type.isTemporary )
  3149. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3150. }
  3151. // Push the reference to the temporary variable on the stack
  3152. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3153. ctx->type.Set(dt);
  3154. ctx->type.isTemporary = true;
  3155. ctx->type.stackOffset = (short)offset;
  3156. ctx->type.isVariable = true;
  3157. ctx->type.isExplicitHandle = isExplicitHandle;
  3158. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  3159. }
  3160. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  3161. {
  3162. // Get return type and location
  3163. sVariable *v = variables->GetVariable("return");
  3164. // Basic validations
  3165. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  3166. {
  3167. Error(TXT_MUST_RETURN_VALUE, rnode);
  3168. return;
  3169. }
  3170. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  3171. {
  3172. Error(TXT_CANT_RETURN_VALUE, rnode);
  3173. return;
  3174. }
  3175. // Compile the expression
  3176. if( rnode->firstChild )
  3177. {
  3178. // Compile the expression
  3179. asSExprContext expr(engine);
  3180. int r = CompileAssignment(rnode->firstChild, &expr);
  3181. if( r < 0 ) return;
  3182. if( v->type.IsReference() )
  3183. {
  3184. // The expression that gives the reference must not use any of the
  3185. // variables that must be destroyed upon exit, because then it means
  3186. // reference will stay alive while the clean-up is done, which could
  3187. // potentially mean that the reference is invalidated by the clean-up.
  3188. //
  3189. // When the function is returning a reference, the clean-up of the
  3190. // variables must be done before the evaluation of the expression.
  3191. //
  3192. // A reference to a global variable, or a class member for class methods
  3193. // should be allowed to be returned.
  3194. if( !(expr.type.dataType.IsReference() ||
  3195. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  3196. {
  3197. // Clean up the potential deferred parameters
  3198. ProcessDeferredParams(&expr);
  3199. Error(TXT_NOT_VALID_REFERENCE, rnode);
  3200. return;
  3201. }
  3202. // No references to local variables, temporary variables, or parameters
  3203. // are allowed to be returned, since they go out of scope when the function
  3204. // returns. Even reference parameters are disallowed, since it is not possible
  3205. // to know the scope of them. The exception is the 'this' pointer, which
  3206. // is treated by the compiler as a local variable, but isn't really so.
  3207. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  3208. {
  3209. // Clean up the potential deferred parameters
  3210. ProcessDeferredParams(&expr);
  3211. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  3212. return;
  3213. }
  3214. // The type must match exactly as we cannot convert
  3215. // the reference without loosing the original value
  3216. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  3217. (expr.type.dataType.IsObject() &&
  3218. !expr.type.dataType.IsObjectHandle() &&
  3219. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  3220. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  3221. {
  3222. // Clean up the potential deferred parameters
  3223. ProcessDeferredParams(&expr);
  3224. asCString str;
  3225. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3226. Error(str, rnode);
  3227. return;
  3228. }
  3229. // The expression must not have any deferred expressions, because the evaluation
  3230. // of these cannot be done without keeping the reference which is not safe
  3231. if( expr.deferredParams.GetLength() )
  3232. {
  3233. // Clean up the potential deferred parameters
  3234. ProcessDeferredParams(&expr);
  3235. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  3236. return;
  3237. }
  3238. // Make sure the expression isn't using any local variables that
  3239. // will need to be cleaned up before the function completes
  3240. asCArray<int> usedVars;
  3241. expr.bc.GetVarsUsed(usedVars);
  3242. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  3243. {
  3244. int var = GetVariableSlot(usedVars[n]);
  3245. if( var != -1 )
  3246. {
  3247. asCDataType dt = variableAllocations[var];
  3248. if( dt.IsObject() )
  3249. {
  3250. ProcessDeferredParams(&expr);
  3251. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  3252. return;
  3253. }
  3254. }
  3255. }
  3256. // All objects in the function must be cleaned up before the expression
  3257. // is evaluated, otherwise there is a possibility that the cleanup will
  3258. // invalidate the reference.
  3259. // Destroy the local variables before loading
  3260. // the reference into the register. This will
  3261. // be done before the expression is evaluated.
  3262. DestroyVariables(bc);
  3263. // For primitives the reference is already in the register,
  3264. // but for non-primitives the reference is on the stack so we
  3265. // need to load it into the register
  3266. if( !expr.type.dataType.IsPrimitive() )
  3267. {
  3268. if( !expr.type.dataType.IsObjectHandle() &&
  3269. expr.type.dataType.IsReference() )
  3270. expr.bc.Instr(asBC_RDSPtr);
  3271. expr.bc.Instr(asBC_PopRPtr);
  3272. }
  3273. // There are no temporaries to release so we're done
  3274. }
  3275. else // if( !v->type.IsReference() )
  3276. {
  3277. ProcessPropertyGetAccessor(&expr, rnode);
  3278. // Prepare the value for assignment
  3279. IsVariableInitialized(&expr.type, rnode->firstChild);
  3280. if( v->type.IsPrimitive() )
  3281. {
  3282. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3283. // Implicitly convert the value to the return type
  3284. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3285. // Verify that the conversion was successful
  3286. if( expr.type.dataType != v->type )
  3287. {
  3288. asCString str;
  3289. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3290. Error(str, rnode);
  3291. return;
  3292. }
  3293. else
  3294. {
  3295. ConvertToVariable(&expr);
  3296. // Clean up the local variables and process deferred parameters
  3297. DestroyVariables(&expr.bc);
  3298. ProcessDeferredParams(&expr);
  3299. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3300. // Load the variable in the register
  3301. if( v->type.GetSizeOnStackDWords() == 1 )
  3302. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3303. else
  3304. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  3305. }
  3306. }
  3307. else if( v->type.IsObject() )
  3308. {
  3309. // Value types are returned on the stack, in a location
  3310. // that has been reserved by the calling function.
  3311. if( outFunc->DoesReturnOnStack() )
  3312. {
  3313. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  3314. // it should be called directly instead of first converting the expression and
  3315. // then copy the value.
  3316. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3317. {
  3318. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3319. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3320. {
  3321. asCString str;
  3322. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3323. Error(str, rnode->firstChild);
  3324. return;
  3325. }
  3326. }
  3327. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  3328. if( v->type.GetObjectType()->beh.copyconstruct )
  3329. {
  3330. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3331. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  3332. }
  3333. else
  3334. {
  3335. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  3336. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, 0, true);
  3337. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3338. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  3339. expr.bc.Instr(asBC_RDSPtr);
  3340. asSExprContext lexpr(engine);
  3341. lexpr.type.Set(v->type);
  3342. lexpr.type.isLValue = true;
  3343. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  3344. expr.bc.Instr(asBC_PopPtr);
  3345. // Release any temporary variable
  3346. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3347. }
  3348. // Clean up the local variables and process deferred parameters
  3349. DestroyVariables(&expr.bc);
  3350. ProcessDeferredParams(&expr);
  3351. }
  3352. else
  3353. {
  3354. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  3355. // Prepare the expression to be loaded into the object
  3356. // register. This will place the reference in local variable
  3357. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  3358. // Pop the reference to the temporary variable
  3359. expr.bc.Instr(asBC_PopPtr);
  3360. // Clean up the local variables and process deferred parameters
  3361. DestroyVariables(&expr.bc);
  3362. ProcessDeferredParams(&expr);
  3363. // Load the object pointer into the object register
  3364. // LOADOBJ also clears the address in the variable
  3365. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  3366. // LOADOBJ cleared the address in the variable so the object will not be freed
  3367. // here, but the temporary variable must still be freed so the slot can be reused
  3368. // By releasing without the bytecode we do just that.
  3369. ReleaseTemporaryVariable(expr.type, 0);
  3370. }
  3371. }
  3372. }
  3373. expr.bc.OptimizeLocally(tempVariableOffsets);
  3374. bc->AddCode(&expr.bc);
  3375. }
  3376. else
  3377. {
  3378. // For functions that don't return anything
  3379. // we just detroy the local variables
  3380. DestroyVariables(bc);
  3381. }
  3382. // Jump to the end of the function
  3383. bc->InstrINT(asBC_JMP, 0);
  3384. }
  3385. void asCCompiler::DestroyVariables(asCByteCode *bc)
  3386. {
  3387. // Call destructor on all variables except for the function parameters
  3388. // Put the clean-up in a block to allow exception handler to understand this
  3389. bc->Block(true);
  3390. asCVariableScope *vs = variables;
  3391. while( vs )
  3392. {
  3393. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3394. if( vs->variables[n]->stackOffset > 0 )
  3395. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3396. vs = vs->parent;
  3397. }
  3398. bc->Block(false);
  3399. }
  3400. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  3401. {
  3402. variables = asNEW(asCVariableScope)(variables);
  3403. if( variables == 0 )
  3404. {
  3405. // Out of memory
  3406. return;
  3407. }
  3408. variables->isBreakScope = isBreakScope;
  3409. variables->isContinueScope = isContinueScope;
  3410. }
  3411. void asCCompiler::RemoveVariableScope()
  3412. {
  3413. if( variables )
  3414. {
  3415. asCVariableScope *var = variables;
  3416. variables = variables->parent;
  3417. asDELETE(var,asCVariableScope);
  3418. }
  3419. }
  3420. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  3421. {
  3422. asCString str;
  3423. int r = 0, c = 0;
  3424. asASSERT( node );
  3425. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3426. builder->WriteError(script->name, msg, r, c);
  3427. hasCompileErrors = true;
  3428. }
  3429. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  3430. {
  3431. asCString str;
  3432. int r = 0, c = 0;
  3433. asASSERT( node );
  3434. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3435. builder->WriteWarning(script->name, msg, r, c);
  3436. }
  3437. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  3438. {
  3439. asCString str;
  3440. int r = 0, c = 0;
  3441. asASSERT( node );
  3442. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3443. builder->WriteInfo(script->name, msg, r, c, false);
  3444. }
  3445. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  3446. {
  3447. int r = 0, c = 0;
  3448. asASSERT( node );
  3449. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3450. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3451. {
  3452. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  3453. builder->WriteInfo(script->name, func->GetDeclaration(true), r, c, false);
  3454. }
  3455. }
  3456. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  3457. {
  3458. int l = int(reservedVariables.GetLength());
  3459. ctx->bc.GetVarsUsed(reservedVariables);
  3460. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  3461. reservedVariables.SetLength(l);
  3462. return var;
  3463. }
  3464. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  3465. {
  3466. asCDataType t(type);
  3467. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  3468. t.SetTokenType(ttInt);
  3469. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  3470. t.SetTokenType(ttDouble);
  3471. // Only null handles have the token type unrecognized token
  3472. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  3473. bool isOnHeap = true;
  3474. if( t.IsPrimitive() ||
  3475. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  3476. {
  3477. // Primitives and value types (unless overridden) are allocated on the stack
  3478. isOnHeap = false;
  3479. }
  3480. // Find a free location with the same type
  3481. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  3482. {
  3483. int slot = freeVariables[n];
  3484. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  3485. variableIsTemporary[slot] == isTemporary &&
  3486. variableIsOnHeap[slot] == isOnHeap )
  3487. {
  3488. // We can't return by slot, must count variable sizes
  3489. int offset = GetVariableOffset(slot);
  3490. // Verify that it is not in the list of reserved variables
  3491. bool isUsed = false;
  3492. if( reservedVariables.GetLength() )
  3493. isUsed = reservedVariables.Exists(offset);
  3494. if( !isUsed )
  3495. {
  3496. if( n != freeVariables.GetLength() - 1 )
  3497. freeVariables[n] = freeVariables.PopLast();
  3498. else
  3499. freeVariables.PopLast();
  3500. if( isTemporary )
  3501. tempVariables.PushLast(offset);
  3502. return offset;
  3503. }
  3504. }
  3505. }
  3506. variableAllocations.PushLast(t);
  3507. variableIsTemporary.PushLast(isTemporary);
  3508. variableIsOnHeap.PushLast(isOnHeap);
  3509. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  3510. if( isTemporary )
  3511. {
  3512. // Add offset to the currently allocated temporary variables
  3513. tempVariables.PushLast(offset);
  3514. // Add offset to all known offsets to temporary variables, whether allocated or not
  3515. tempVariableOffsets.PushLast(offset);
  3516. }
  3517. return offset;
  3518. }
  3519. int asCCompiler::GetVariableOffset(int varIndex)
  3520. {
  3521. // Return offset to the last dword on the stack
  3522. int varOffset = 1;
  3523. for( int n = 0; n < varIndex; n++ )
  3524. {
  3525. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3526. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  3527. else
  3528. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  3529. }
  3530. if( varIndex < (int)variableAllocations.GetLength() )
  3531. {
  3532. int size;
  3533. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  3534. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  3535. else
  3536. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  3537. if( size > 1 )
  3538. varOffset += size-1;
  3539. }
  3540. return varOffset;
  3541. }
  3542. int asCCompiler::GetVariableSlot(int offset)
  3543. {
  3544. int varOffset = 1;
  3545. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  3546. {
  3547. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3548. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  3549. else
  3550. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  3551. if( varOffset == offset )
  3552. return n;
  3553. varOffset++;
  3554. }
  3555. return -1;
  3556. }
  3557. bool asCCompiler::IsVariableOnHeap(int offset)
  3558. {
  3559. int varSlot = GetVariableSlot(offset);
  3560. if( varSlot < 0 )
  3561. {
  3562. // This happens for function arguments that are considered as on the heap
  3563. return true;
  3564. }
  3565. return variableIsOnHeap[varSlot];
  3566. }
  3567. void asCCompiler::DeallocateVariable(int offset)
  3568. {
  3569. // Remove temporary variable
  3570. int n;
  3571. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  3572. {
  3573. if( offset == tempVariables[n] )
  3574. {
  3575. if( n == (int)tempVariables.GetLength()-1 )
  3576. tempVariables.PopLast();
  3577. else
  3578. tempVariables[n] = tempVariables.PopLast();
  3579. break;
  3580. }
  3581. }
  3582. n = GetVariableSlot(offset);
  3583. if( n != -1 )
  3584. {
  3585. freeVariables.PushLast(n);
  3586. return;
  3587. }
  3588. // We might get here if the variable was implicitly declared
  3589. // because it was use before a formal declaration, in this case
  3590. // the offset is 0x7FFF
  3591. asASSERT(offset == 0x7FFF);
  3592. }
  3593. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  3594. {
  3595. if( t.isTemporary )
  3596. {
  3597. ReleaseTemporaryVariable(t.stackOffset, bc);
  3598. t.isTemporary = false;
  3599. }
  3600. }
  3601. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  3602. {
  3603. if( bc )
  3604. {
  3605. // We need to call the destructor on the true variable type
  3606. int n = GetVariableSlot(offset);
  3607. asASSERT( n >= 0 );
  3608. if( n >= 0 )
  3609. {
  3610. asCDataType dt = variableAllocations[n];
  3611. bool isOnHeap = variableIsOnHeap[n];
  3612. // Call destructor
  3613. CallDestructor(dt, offset, isOnHeap, bc);
  3614. }
  3615. }
  3616. DeallocateVariable(offset);
  3617. }
  3618. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  3619. {
  3620. if( ctx->type.dataType.IsReference() )
  3621. {
  3622. if( ctx->type.dataType.IsObject() )
  3623. {
  3624. ctx->type.dataType.MakeReference(false);
  3625. if( generateCode )
  3626. ctx->bc.Instr(asBC_RDSPtr);
  3627. }
  3628. else
  3629. {
  3630. // This should never happen as primitives are treated differently
  3631. asASSERT(false);
  3632. }
  3633. }
  3634. }
  3635. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  3636. {
  3637. // No need to check if there is no variable scope
  3638. if( variables == 0 ) return true;
  3639. // Temporary variables are assumed to be initialized
  3640. if( type->isTemporary ) return true;
  3641. // Verify that it is a variable
  3642. if( !type->isVariable ) return true;
  3643. // Find the variable
  3644. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  3645. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  3646. if( v == 0 ) return true;
  3647. if( v->isInitialized ) return true;
  3648. // Complex types don't need this test
  3649. if( v->type.IsObject() ) return true;
  3650. // Mark as initialized so that the user will not be bothered again
  3651. v->isInitialized = true;
  3652. // Write warning
  3653. asCString str;
  3654. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  3655. Warning(str, node);
  3656. return false;
  3657. }
  3658. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  3659. {
  3660. // Check if the variable is initialized (if it indeed is a variable)
  3661. IsVariableInitialized(&ctx->type, node);
  3662. asCDataType to = ctx->type.dataType;
  3663. to.MakeReference(false);
  3664. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  3665. ProcessDeferredParams(ctx);
  3666. }
  3667. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  3668. {
  3669. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  3670. int l = int(reservedVariables.GetLength());
  3671. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  3672. ProcessPropertyGetAccessor(rctx, node);
  3673. // Make sure the rvalue is initialized if it is a variable
  3674. IsVariableInitialized(&rctx->type, node);
  3675. if( lvalue->IsPrimitive() )
  3676. {
  3677. if( rctx->type.dataType.IsPrimitive() )
  3678. {
  3679. if( rctx->type.dataType.IsReference() )
  3680. {
  3681. // Cannot do implicit conversion of references so we first convert the reference to a variable
  3682. ConvertToVariableNotIn(rctx, lvalueExpr);
  3683. }
  3684. }
  3685. // Implicitly convert the value to the right type
  3686. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  3687. // Check data type
  3688. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3689. {
  3690. asCString str;
  3691. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3692. Error(str, node);
  3693. rctx->type.SetDummy();
  3694. }
  3695. // Make sure the rvalue is a variable
  3696. if( !rctx->type.isVariable )
  3697. ConvertToVariableNotIn(rctx, lvalueExpr);
  3698. }
  3699. else
  3700. {
  3701. asCDataType to = *lvalue;
  3702. to.MakeReference(false);
  3703. // TODO: ImplicitConversion should know to do this by itself
  3704. // First convert to a handle which will do a reference cast
  3705. if( !lvalue->IsObjectHandle() &&
  3706. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3707. to.MakeHandle(true);
  3708. // Don't allow the implicit conversion to create an object
  3709. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3710. if( !lvalue->IsObjectHandle() &&
  3711. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3712. {
  3713. // Then convert to a reference, which will validate the handle
  3714. to.MakeHandle(false);
  3715. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3716. }
  3717. // Check data type
  3718. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3719. {
  3720. asCString str;
  3721. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3722. Error(str, node);
  3723. }
  3724. else
  3725. {
  3726. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3727. if( lvalue->IsObject() )
  3728. asASSERT(!rctx->type.dataType.IsReference());
  3729. }
  3730. }
  3731. // Unreserve variables
  3732. reservedVariables.SetLength(l);
  3733. }
  3734. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3735. {
  3736. if( !type.isLValue ) return false;
  3737. if( type.dataType.IsReadOnly() ) return false;
  3738. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3739. return true;
  3740. }
  3741. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3742. {
  3743. if( lvalue->dataType.IsReadOnly() )
  3744. {
  3745. Error(TXT_REF_IS_READ_ONLY, node);
  3746. return -1;
  3747. }
  3748. if( lvalue->dataType.IsPrimitive() )
  3749. {
  3750. if( lvalue->isVariable )
  3751. {
  3752. // Copy the value between the variables directly
  3753. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3754. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3755. else
  3756. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3757. // Mark variable as initialized
  3758. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3759. if( v ) v->isInitialized = true;
  3760. }
  3761. else if( lvalue->dataType.IsReference() )
  3762. {
  3763. // Copy the value of the variable to the reference in the register
  3764. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3765. if( s == 1 )
  3766. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3767. else if( s == 2 )
  3768. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3769. else if( s == 4 )
  3770. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3771. else if( s == 8 )
  3772. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3773. }
  3774. else
  3775. {
  3776. Error(TXT_NOT_VALID_LVALUE, node);
  3777. return -1;
  3778. }
  3779. }
  3780. else if( !lvalue->isExplicitHandle )
  3781. {
  3782. asSExprContext ctx(engine);
  3783. ctx.type = *lvalue;
  3784. Dereference(&ctx, true);
  3785. *lvalue = ctx.type;
  3786. bc->AddCode(&ctx.bc);
  3787. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3788. // The beh->copy member will be removed.
  3789. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3790. if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  3791. {
  3792. asSExprContext res(engine);
  3793. PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType());
  3794. bc->AddCode(&res.bc);
  3795. *lvalue = res.type;
  3796. }
  3797. else if( beh->copy == engine->scriptTypeBehaviours.beh.copy )
  3798. {
  3799. // Call the default copy operator for script classes
  3800. // This is done differently because the default copy operator
  3801. // is registered as returning int&, but in reality it returns
  3802. // a reference to the object.
  3803. // TODO: Avoid this special case by implementing a copystub for
  3804. // script classes that uses the default copy operator
  3805. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  3806. bc->Instr(asBC_PshRPtr);
  3807. }
  3808. else
  3809. {
  3810. // Default copy operator
  3811. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3812. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3813. {
  3814. asCString msg;
  3815. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  3816. Error(msg, node);
  3817. return -1;
  3818. }
  3819. // Copy larger data types from a reference
  3820. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  3821. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3822. }
  3823. }
  3824. else
  3825. {
  3826. // TODO: The object handle can be stored in a variable as well
  3827. if( !lvalue->dataType.IsReference() )
  3828. {
  3829. Error(TXT_NOT_VALID_REFERENCE, node);
  3830. return -1;
  3831. }
  3832. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3833. // Mark variable as initialized
  3834. if( variables )
  3835. {
  3836. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3837. if( v ) v->isInitialized = true;
  3838. }
  3839. }
  3840. return 0;
  3841. }
  3842. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3843. {
  3844. bool conversionDone = false;
  3845. asCArray<int> ops;
  3846. asUINT n;
  3847. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3848. {
  3849. // We need it to be a reference
  3850. if( !ctx->type.dataType.IsReference() )
  3851. {
  3852. asCDataType to = ctx->type.dataType;
  3853. to.MakeReference(true);
  3854. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3855. }
  3856. if( isExplicit )
  3857. {
  3858. // Allow dynamic cast between object handles (only for script objects).
  3859. // At run time this may result in a null handle,
  3860. // which when used will throw an exception
  3861. conversionDone = true;
  3862. if( generateCode )
  3863. {
  3864. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3865. // Allocate a temporary variable for the returned object
  3866. int returnOffset = AllocateVariable(to, true);
  3867. // Move the pointer from the object register to the temporary variable
  3868. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3869. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3870. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3871. ctx->type.SetVariable(to, returnOffset, true);
  3872. ctx->type.dataType.MakeReference(true);
  3873. }
  3874. else
  3875. {
  3876. ctx->type.dataType = to;
  3877. ctx->type.dataType.MakeReference(true);
  3878. }
  3879. }
  3880. else
  3881. {
  3882. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3883. {
  3884. conversionDone = true;
  3885. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3886. }
  3887. }
  3888. }
  3889. else
  3890. {
  3891. // Find a suitable registered behaviour
  3892. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3893. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3894. {
  3895. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3896. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3897. {
  3898. int funcId = beh->operators[n+1];
  3899. // Is the operator for the output type?
  3900. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3901. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3902. continue;
  3903. ops.PushLast(funcId);
  3904. }
  3905. }
  3906. // It shouldn't be possible to have more than one
  3907. asASSERT( ops.GetLength() <= 1 );
  3908. // Should only have one behaviour for each output type
  3909. if( ops.GetLength() == 1 )
  3910. {
  3911. if( generateCode )
  3912. {
  3913. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  3914. // null, we can create a special CALLSYS instruction that checks
  3915. // if the object pointer is null and if so sets the object register
  3916. // to null directly without executing the function.
  3917. //
  3918. // Alternatively I could force the ref cast behaviours be global
  3919. // functions with 1 parameter, even though they should still be
  3920. // registered with RegisterObjectBehaviour()
  3921. // Add code to avoid calling the cast behaviour if the handle is already null,
  3922. // because that will raise a null pointer exception due to the cast behaviour
  3923. // being a class method, and the this pointer cannot be null.
  3924. if( ctx->type.isVariable )
  3925. ctx->bc.Instr(asBC_PopPtr);
  3926. else
  3927. {
  3928. Dereference(ctx, true);
  3929. ConvertToVariable(ctx);
  3930. }
  3931. // TODO: runtime optimize: should have immediate comparison for null pointer
  3932. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  3933. // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
  3934. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  3935. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  3936. DeallocateVariable(offset);
  3937. int afterLabel = nextLabel++;
  3938. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3939. // Call the cast operator
  3940. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3941. ctx->bc.Instr(asBC_RDSPtr);
  3942. ctx->type.dataType.MakeReference(false);
  3943. asCTypeInfo objType = ctx->type;
  3944. asCArray<asSExprContext *> args;
  3945. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3946. ctx->bc.Instr(asBC_PopPtr);
  3947. int endLabel = nextLabel++;
  3948. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3949. ctx->bc.Label((short)afterLabel);
  3950. // Make a NULL pointer
  3951. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  3952. ctx->bc.Label((short)endLabel);
  3953. // Since we're receiving a handle, we can release the original variable
  3954. ReleaseTemporaryVariable(objType, &ctx->bc);
  3955. // Push the reference to the handle on the stack
  3956. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3957. }
  3958. else
  3959. {
  3960. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3961. ctx->type.Set(func->returnType);
  3962. }
  3963. }
  3964. else if( ops.GetLength() == 0 )
  3965. {
  3966. // Check for the generic ref cast behaviour
  3967. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3968. {
  3969. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3970. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3971. {
  3972. int funcId = beh->operators[n+1];
  3973. // Does the operator take the ?&out parameter?
  3974. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3975. if( func->parameterTypes.GetLength() != 1 ||
  3976. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3977. func->inOutFlags[0] != asTM_OUTREF )
  3978. continue;
  3979. ops.PushLast(funcId);
  3980. }
  3981. }
  3982. // It shouldn't be possible to have more than one
  3983. asASSERT( ops.GetLength() <= 1 );
  3984. if( ops.GetLength() == 1 )
  3985. {
  3986. if( generateCode )
  3987. {
  3988. asASSERT(to.IsObjectHandle());
  3989. // Allocate a temporary variable of the requested handle type
  3990. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  3991. // Pass the reference of that variable to the function as output parameter
  3992. asCDataType toRef(to);
  3993. toRef.MakeReference(true);
  3994. asCArray<asSExprContext *> args;
  3995. asSExprContext arg(engine);
  3996. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3997. // Don't mark the variable as temporary, so it won't be freed too early
  3998. arg.type.SetVariable(toRef, stackOffset, false);
  3999. arg.type.isLValue = true;
  4000. arg.type.isExplicitHandle = true;
  4001. args.PushLast(&arg);
  4002. asCTypeInfo prev = ctx->type;
  4003. // Call the behaviour method
  4004. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  4005. // Release previous temporary variable
  4006. ReleaseTemporaryVariable(prev, &ctx->bc);
  4007. // Use the reference to the variable as the result of the expression
  4008. // Now we can mark the variable as temporary
  4009. ctx->type.SetVariable(toRef, stackOffset, true);
  4010. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4011. }
  4012. else
  4013. {
  4014. // All casts are legal
  4015. ctx->type.Set(to);
  4016. }
  4017. }
  4018. }
  4019. }
  4020. return conversionDone;
  4021. }
  4022. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4023. {
  4024. asCDataType to = toOrig;
  4025. to.MakeReference(false);
  4026. asASSERT( !ctx->type.dataType.IsReference() );
  4027. // Maybe no conversion is needed
  4028. if( to.IsEqualExceptConst(ctx->type.dataType) )
  4029. {
  4030. // A primitive is const or not
  4031. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4032. return asCC_NO_CONV;
  4033. }
  4034. // Determine the cost of this conversion
  4035. asUINT cost = asCC_NO_CONV;
  4036. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4037. cost = asCC_INT_FLOAT_CONV;
  4038. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
  4039. cost = asCC_INT_FLOAT_CONV;
  4040. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  4041. cost = asCC_SIGNED_CONV;
  4042. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  4043. cost = asCC_SIGNED_CONV;
  4044. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  4045. cost = asCC_PRIMITIVE_SIZE_CONV;
  4046. // Start by implicitly converting constant values
  4047. if( ctx->type.isConstant )
  4048. {
  4049. ImplicitConversionConstant(ctx, to, node, convType);
  4050. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4051. return cost;
  4052. }
  4053. // Allow implicit conversion between numbers
  4054. if( generateCode )
  4055. {
  4056. // When generating the code the decision has already been made, so we don't bother determining the cost
  4057. // Convert smaller types to 32bit first
  4058. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  4059. if( s < 4 )
  4060. {
  4061. ConvertToTempVariable(ctx);
  4062. if( ctx->type.dataType.IsIntegerType() )
  4063. {
  4064. if( s == 1 )
  4065. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  4066. else if( s == 2 )
  4067. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  4068. ctx->type.dataType.SetTokenType(ttInt);
  4069. }
  4070. else if( ctx->type.dataType.IsUnsignedType() )
  4071. {
  4072. if( s == 1 )
  4073. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  4074. else if( s == 2 )
  4075. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  4076. ctx->type.dataType.SetTokenType(ttUInt);
  4077. }
  4078. }
  4079. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  4080. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4081. {
  4082. if( ctx->type.dataType.IsIntegerType() ||
  4083. ctx->type.dataType.IsUnsignedType() )
  4084. {
  4085. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4086. {
  4087. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4088. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4089. }
  4090. else
  4091. {
  4092. ConvertToTempVariable(ctx);
  4093. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4094. int offset = AllocateVariable(to, true);
  4095. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4096. ctx->type.SetVariable(to, offset, true);
  4097. }
  4098. }
  4099. else if( ctx->type.dataType.IsFloatType() )
  4100. {
  4101. ConvertToTempVariable(ctx);
  4102. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  4103. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4104. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4105. if( convType != asIC_EXPLICIT_VAL_CAST )
  4106. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4107. }
  4108. else if( ctx->type.dataType.IsDoubleType() )
  4109. {
  4110. ConvertToTempVariable(ctx);
  4111. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4112. int offset = AllocateVariable(to, true);
  4113. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  4114. ctx->type.SetVariable(to, offset, true);
  4115. if( convType != asIC_EXPLICIT_VAL_CAST )
  4116. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4117. }
  4118. // Convert to smaller integer if necessary
  4119. int s = to.GetSizeInMemoryBytes();
  4120. if( s < 4 )
  4121. {
  4122. ConvertToTempVariable(ctx);
  4123. if( s == 1 )
  4124. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4125. else if( s == 2 )
  4126. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4127. }
  4128. }
  4129. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4130. {
  4131. if( ctx->type.dataType.IsIntegerType() ||
  4132. ctx->type.dataType.IsUnsignedType() )
  4133. {
  4134. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4135. {
  4136. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4137. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4138. }
  4139. else
  4140. {
  4141. ConvertToTempVariable(ctx);
  4142. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4143. int offset = AllocateVariable(to, true);
  4144. if( ctx->type.dataType.IsUnsignedType() )
  4145. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4146. else
  4147. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4148. ctx->type.SetVariable(to, offset, true);
  4149. }
  4150. }
  4151. else if( ctx->type.dataType.IsFloatType() )
  4152. {
  4153. ConvertToTempVariable(ctx);
  4154. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4155. int offset = AllocateVariable(to, true);
  4156. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  4157. ctx->type.SetVariable(to, offset, true);
  4158. if( convType != asIC_EXPLICIT_VAL_CAST )
  4159. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4160. }
  4161. else if( ctx->type.dataType.IsDoubleType() )
  4162. {
  4163. ConvertToTempVariable(ctx);
  4164. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  4165. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4166. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4167. if( convType != asIC_EXPLICIT_VAL_CAST )
  4168. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4169. }
  4170. }
  4171. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4172. {
  4173. if( ctx->type.dataType.IsIntegerType() ||
  4174. ctx->type.dataType.IsUnsignedType() )
  4175. {
  4176. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4177. {
  4178. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4179. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4180. }
  4181. else
  4182. {
  4183. ConvertToTempVariable(ctx);
  4184. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4185. int offset = AllocateVariable(to, true);
  4186. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4187. ctx->type.SetVariable(to, offset, true);
  4188. }
  4189. }
  4190. else if( ctx->type.dataType.IsFloatType() )
  4191. {
  4192. ConvertToTempVariable(ctx);
  4193. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  4194. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4195. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4196. if( convType != asIC_EXPLICIT_VAL_CAST )
  4197. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4198. }
  4199. else if( ctx->type.dataType.IsDoubleType() )
  4200. {
  4201. ConvertToTempVariable(ctx);
  4202. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4203. int offset = AllocateVariable(to, true);
  4204. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  4205. ctx->type.SetVariable(to, offset, true);
  4206. if( convType != asIC_EXPLICIT_VAL_CAST )
  4207. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4208. }
  4209. // Convert to smaller integer if necessary
  4210. int s = to.GetSizeInMemoryBytes();
  4211. if( s < 4 )
  4212. {
  4213. ConvertToTempVariable(ctx);
  4214. if( s == 1 )
  4215. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4216. else if( s == 2 )
  4217. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4218. }
  4219. }
  4220. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4221. {
  4222. if( ctx->type.dataType.IsIntegerType() ||
  4223. ctx->type.dataType.IsUnsignedType() )
  4224. {
  4225. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4226. {
  4227. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4228. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4229. }
  4230. else
  4231. {
  4232. ConvertToTempVariable(ctx);
  4233. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4234. int offset = AllocateVariable(to, true);
  4235. if( ctx->type.dataType.IsUnsignedType() )
  4236. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4237. else
  4238. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4239. ctx->type.SetVariable(to, offset, true);
  4240. }
  4241. }
  4242. else if( ctx->type.dataType.IsFloatType() )
  4243. {
  4244. ConvertToTempVariable(ctx);
  4245. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4246. int offset = AllocateVariable(to, true);
  4247. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  4248. ctx->type.SetVariable(to, offset, true);
  4249. if( convType != asIC_EXPLICIT_VAL_CAST )
  4250. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4251. }
  4252. else if( ctx->type.dataType.IsDoubleType() )
  4253. {
  4254. ConvertToTempVariable(ctx);
  4255. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  4256. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4257. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4258. if( convType != asIC_EXPLICIT_VAL_CAST )
  4259. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4260. }
  4261. }
  4262. else if( to.IsFloatType() )
  4263. {
  4264. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4265. {
  4266. ConvertToTempVariable(ctx);
  4267. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  4268. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4269. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4270. }
  4271. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4272. {
  4273. ConvertToTempVariable(ctx);
  4274. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4275. int offset = AllocateVariable(to, true);
  4276. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  4277. ctx->type.SetVariable(to, offset, true);
  4278. }
  4279. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4280. {
  4281. ConvertToTempVariable(ctx);
  4282. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  4283. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4284. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4285. }
  4286. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4287. {
  4288. ConvertToTempVariable(ctx);
  4289. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4290. int offset = AllocateVariable(to, true);
  4291. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  4292. ctx->type.SetVariable(to, offset, true);
  4293. }
  4294. else if( ctx->type.dataType.IsDoubleType() )
  4295. {
  4296. ConvertToTempVariable(ctx);
  4297. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4298. int offset = AllocateVariable(to, true);
  4299. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  4300. ctx->type.SetVariable(to, offset, true);
  4301. }
  4302. }
  4303. else if( to.IsDoubleType() )
  4304. {
  4305. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4306. {
  4307. ConvertToTempVariable(ctx);
  4308. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4309. int offset = AllocateVariable(to, true);
  4310. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  4311. ctx->type.SetVariable(to, offset, true);
  4312. }
  4313. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4314. {
  4315. ConvertToTempVariable(ctx);
  4316. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  4317. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4318. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4319. }
  4320. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4321. {
  4322. ConvertToTempVariable(ctx);
  4323. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4324. int offset = AllocateVariable(to, true);
  4325. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  4326. ctx->type.SetVariable(to, offset, true);
  4327. }
  4328. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4329. {
  4330. ConvertToTempVariable(ctx);
  4331. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  4332. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4333. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4334. }
  4335. else if( ctx->type.dataType.IsFloatType() )
  4336. {
  4337. ConvertToTempVariable(ctx);
  4338. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4339. int offset = AllocateVariable(to, true);
  4340. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  4341. ctx->type.SetVariable(to, offset, true);
  4342. }
  4343. }
  4344. }
  4345. else
  4346. {
  4347. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  4348. to.IsFloatType() || to.IsDoubleType() ||
  4349. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  4350. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  4351. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4352. {
  4353. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4354. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4355. }
  4356. }
  4357. // Primitive types on the stack, can be const or non-const
  4358. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4359. return cost;
  4360. }
  4361. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4362. {
  4363. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  4364. ctx->type.dataType.IsNullHandle() );
  4365. // No conversion from void to any other type
  4366. if( ctx->type.dataType.GetTokenType() == ttVoid )
  4367. return asCC_NO_CONV;
  4368. // Do we want a var type?
  4369. if( to.GetTokenType() == ttQuestion )
  4370. {
  4371. // Any type can be converted to a var type, but only when not generating code
  4372. asASSERT( !generateCode );
  4373. ctx->type.dataType = to;
  4374. return asCC_VARIABLE_CONV;
  4375. }
  4376. // Do we want a primitive?
  4377. else if( to.IsPrimitive() )
  4378. {
  4379. if( !ctx->type.dataType.IsPrimitive() )
  4380. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  4381. else
  4382. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  4383. }
  4384. else // The target is a complex type
  4385. {
  4386. if( ctx->type.dataType.IsPrimitive() )
  4387. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4388. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  4389. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4390. }
  4391. return asCC_NO_CONV;
  4392. }
  4393. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4394. {
  4395. if( ctx->type.isExplicitHandle )
  4396. {
  4397. // An explicit handle cannot be converted to a primitive
  4398. if( convType != asIC_IMPLICIT_CONV && node )
  4399. {
  4400. asCString str;
  4401. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4402. Error(str, node);
  4403. }
  4404. return asCC_NO_CONV;
  4405. }
  4406. // TODO: Must use the const cast behaviour if the object is read-only
  4407. // Find matching value cast behaviours
  4408. // Here we're only interested in those that convert the type to a primitive type
  4409. asCArray<int> funcs;
  4410. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4411. if( beh )
  4412. {
  4413. if( convType == asIC_EXPLICIT_VAL_CAST )
  4414. {
  4415. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4416. {
  4417. // accept both implicit and explicit cast
  4418. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4419. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4420. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4421. funcs.PushLast(beh->operators[n+1]);
  4422. }
  4423. }
  4424. else
  4425. {
  4426. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4427. {
  4428. // accept only implicit cast
  4429. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4430. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4431. funcs.PushLast(beh->operators[n+1]);
  4432. }
  4433. }
  4434. }
  4435. // This matrix describes the priorities of the types to search for, for each target type
  4436. // The first column is the target type, the priorities goes from left to right
  4437. eTokenType matchMtx[10][10] =
  4438. {
  4439. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4440. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4441. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4442. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4443. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4444. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4445. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  4446. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  4447. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  4448. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  4449. };
  4450. // Which row to use?
  4451. eTokenType *row = 0;
  4452. for( unsigned int type = 0; type < 10; type++ )
  4453. {
  4454. if( to.GetTokenType() == matchMtx[type][0] )
  4455. {
  4456. row = &matchMtx[type][0];
  4457. break;
  4458. }
  4459. }
  4460. // Find the best matching cast operator
  4461. int funcId = 0;
  4462. if( row )
  4463. {
  4464. asCDataType target(to);
  4465. // Priority goes from left to right in the matrix
  4466. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  4467. {
  4468. target.SetTokenType(row[attempt]);
  4469. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4470. {
  4471. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  4472. if( descr->returnType.IsEqualExceptConst(target) )
  4473. {
  4474. funcId = funcs[n];
  4475. break;
  4476. }
  4477. }
  4478. }
  4479. }
  4480. // Did we find a suitable function?
  4481. if( funcId != 0 )
  4482. {
  4483. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  4484. if( generateCode )
  4485. {
  4486. asCTypeInfo objType = ctx->type;
  4487. Dereference(ctx, true);
  4488. PerformFunctionCall(funcId, ctx);
  4489. ReleaseTemporaryVariable(objType, &ctx->bc);
  4490. }
  4491. else
  4492. ctx->type.Set(descr->returnType);
  4493. // Allow one more implicit conversion to another primitive type
  4494. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  4495. }
  4496. else
  4497. {
  4498. if( convType != asIC_IMPLICIT_CONV && node )
  4499. {
  4500. asCString str;
  4501. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4502. Error(str, node);
  4503. }
  4504. }
  4505. return asCC_NO_CONV;
  4506. }
  4507. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4508. {
  4509. // Convert null to any object type handle, but not to a non-handle type
  4510. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  4511. {
  4512. if( to.IsObjectHandle() )
  4513. {
  4514. ctx->type.dataType = to;
  4515. return asCC_REF_CONV;
  4516. }
  4517. return asCC_NO_CONV;
  4518. }
  4519. asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
  4520. // First attempt to convert the base type without instanciating another instance
  4521. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
  4522. {
  4523. // If the to type is an interface and the from type implements it, then we can convert it immediately
  4524. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  4525. {
  4526. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4527. return asCC_REF_CONV;
  4528. }
  4529. // If the to type is a class and the from type derives from it, then we can convert it immediately
  4530. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4531. {
  4532. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4533. return asCC_REF_CONV;
  4534. }
  4535. // If the types are not equal yet, then we may still be able to find a reference cast
  4536. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  4537. {
  4538. // A ref cast must not remove the constness
  4539. bool isConst = false;
  4540. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  4541. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  4542. isConst = true;
  4543. // We may still be able to find an implicit ref cast behaviour
  4544. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  4545. ctx->type.dataType.MakeHandleToConst(isConst);
  4546. // Was the conversion done?
  4547. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  4548. return asCC_REF_CONV;
  4549. }
  4550. }
  4551. // Convert matching function types
  4552. if( to.GetFuncDef() )
  4553. {
  4554. // If the input expression is already a funcdef, check if it can be converted
  4555. if( ctx->type.dataType.GetFuncDef() &&
  4556. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  4557. {
  4558. asCScriptFunction *toFunc = to.GetFuncDef();
  4559. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  4560. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  4561. {
  4562. ctx->type.dataType.SetFuncDef(toFunc);
  4563. return asCC_REF_CONV;
  4564. }
  4565. }
  4566. // If the input expression is a deferred function ref, check if there is a matching func
  4567. if( ctx->methodName != "" )
  4568. {
  4569. // Determine the namespace
  4570. asSNameSpace *ns = 0;
  4571. asCString name = "";
  4572. int pos = ctx->methodName.FindLast("::");
  4573. if( pos >= 0 )
  4574. {
  4575. asCString nsName = ctx->methodName.SubString(0, pos+2);
  4576. // Trim off the last ::
  4577. if( nsName.GetLength() > 2 )
  4578. nsName.SetLength(nsName.GetLength()-2);
  4579. ns = DetermineNameSpace(nsName);
  4580. name = ctx->methodName.SubString(pos+2);
  4581. }
  4582. else
  4583. {
  4584. DetermineNameSpace("");
  4585. name = ctx->methodName;
  4586. }
  4587. asCArray<int> funcs;
  4588. if( ns )
  4589. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  4590. // Check if any of the functions have perfect match
  4591. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  4592. {
  4593. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4594. if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
  4595. {
  4596. if( generateCode )
  4597. {
  4598. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  4599. // Make sure the identified function is shared if we're compiling a shared function
  4600. if( !func->IsShared() && outFunc->IsShared() )
  4601. {
  4602. asCString msg;
  4603. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  4604. Error(msg, node);
  4605. }
  4606. }
  4607. ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
  4608. return asCC_REF_CONV;
  4609. }
  4610. }
  4611. }
  4612. }
  4613. return asCC_NO_CONV;
  4614. }
  4615. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv convType, bool generateCode)
  4616. {
  4617. asUINT cost = asCC_NO_CONV;
  4618. // If the base type is still different, and we are allowed to instance
  4619. // another object then we can try an implicit value cast
  4620. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4621. {
  4622. // TODO: Implement support for implicit constructor/factory
  4623. asCArray<int> funcs;
  4624. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4625. if( beh )
  4626. {
  4627. if( convType == asIC_EXPLICIT_VAL_CAST )
  4628. {
  4629. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4630. {
  4631. // accept both implicit and explicit cast
  4632. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4633. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4634. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4635. funcs.PushLast(beh->operators[n+1]);
  4636. }
  4637. }
  4638. else
  4639. {
  4640. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4641. {
  4642. // accept only implicit cast
  4643. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4644. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4645. funcs.PushLast(beh->operators[n+1]);
  4646. }
  4647. }
  4648. }
  4649. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  4650. asASSERT( funcs.GetLength() <= 1 );
  4651. if( funcs.GetLength() == 1 )
  4652. {
  4653. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  4654. if( generateCode )
  4655. {
  4656. asCTypeInfo objType = ctx->type;
  4657. Dereference(ctx, true);
  4658. bool useVariable = false;
  4659. int stackOffset = 0;
  4660. if( f->DoesReturnOnStack() )
  4661. {
  4662. useVariable = true;
  4663. stackOffset = AllocateVariable(f->returnType, true);
  4664. // Push the pointer to the pre-allocated space for the return value
  4665. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  4666. // The object pointer is already on the stack, but should be the top
  4667. // one, so we need to swap the pointers in order to get the correct
  4668. ctx->bc.Instr(asBC_SwapPtr);
  4669. }
  4670. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  4671. ReleaseTemporaryVariable(objType, &ctx->bc);
  4672. }
  4673. else
  4674. ctx->type.Set(f->returnType);
  4675. cost = asCC_TO_OBJECT_CONV;
  4676. }
  4677. }
  4678. return cost;
  4679. }
  4680. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4681. {
  4682. // First try a ref cast
  4683. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  4684. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  4685. // construct the object through any of the available constructors
  4686. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4687. {
  4688. asCArray<int> funcs;
  4689. funcs = to.GetObjectType()->beh.constructors;
  4690. asCArray<asSExprContext *> args;
  4691. args.PushLast(ctx);
  4692. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, false, true, false);
  4693. // Did we find a matching constructor?
  4694. if( funcs.GetLength() == 1 )
  4695. {
  4696. if( generateCode )
  4697. {
  4698. // If the ASHANDLE receives a variable type parameter, then we need to
  4699. // make sure the expression is treated as a handle and not as a value
  4700. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  4701. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  4702. {
  4703. if( !ctx->type.isExplicitHandle )
  4704. {
  4705. asCDataType toHandle = ctx->type.dataType;
  4706. toHandle.MakeHandle(true);
  4707. toHandle.MakeReference(true);
  4708. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  4709. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  4710. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4711. }
  4712. ctx->type.isExplicitHandle = true;
  4713. }
  4714. // TODO: This should really reuse the code from CompileConstructCall
  4715. // Allocate the new object
  4716. asCTypeInfo tempObj;
  4717. tempObj.dataType = to;
  4718. tempObj.dataType.MakeReference(false);
  4719. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  4720. tempObj.dataType.MakeReference(true);
  4721. tempObj.isTemporary = true;
  4722. tempObj.isVariable = true;
  4723. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4724. // Push the address of the object on the stack
  4725. asSExprContext e(engine);
  4726. if( onHeap )
  4727. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4728. PrepareFunctionCall(funcs[0], &e.bc, args);
  4729. MoveArgsToStack(funcs[0], &e.bc, args, false);
  4730. // If the object is allocated on the stack, then call the constructor as a normal function
  4731. if( onHeap )
  4732. {
  4733. int offset = 0;
  4734. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4735. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  4736. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4737. }
  4738. else
  4739. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4740. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  4741. // Add tag that the object has been initialized
  4742. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4743. // The constructor doesn't return anything,
  4744. // so we have to manually inform the type of
  4745. // the return value
  4746. e.type = tempObj;
  4747. if( !onHeap )
  4748. e.type.dataType.MakeReference(false);
  4749. // Push the address of the object on the stack again
  4750. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4751. MergeExprBytecodeAndType(ctx, &e);
  4752. }
  4753. else
  4754. {
  4755. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  4756. }
  4757. }
  4758. }
  4759. // If the base type is still different, and we are allowed to instance
  4760. // another object then we can try an implicit value cast
  4761. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4762. {
  4763. // Attempt implicit value cast
  4764. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  4765. }
  4766. // If we still haven't converted the base type to the correct type, then there is
  4767. // no need to continue as it is not possible to do the conversion
  4768. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4769. return asCC_NO_CONV;
  4770. if( to.IsObjectHandle() )
  4771. {
  4772. // There is no extra cost in converting to a handle
  4773. // reference to handle -> handle
  4774. // reference -> handle
  4775. // object -> handle
  4776. // handle -> reference to handle
  4777. // reference -> reference to handle
  4778. // object -> reference to handle
  4779. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  4780. // If the rvalue is a handle to a const object, then
  4781. // the lvalue must also be a handle to a const object
  4782. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  4783. {
  4784. if( convType != asIC_IMPLICIT_CONV )
  4785. {
  4786. asASSERT(node);
  4787. asCString str;
  4788. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4789. Error(str, node);
  4790. }
  4791. }
  4792. if( !ctx->type.dataType.IsObjectHandle() )
  4793. {
  4794. // An object type can be directly converted to a handle of the
  4795. // same type by doing a ref copy to a new variable
  4796. if( ctx->type.dataType.SupportHandles() )
  4797. {
  4798. asCDataType dt = ctx->type.dataType;
  4799. dt.MakeHandle(true);
  4800. dt.MakeReference(false);
  4801. if( generateCode )
  4802. {
  4803. // If the expression is already a local variable, then it is not
  4804. // necessary to do a ref copy, as the ref objects on the stack are
  4805. // really handles, only the handles cannot be modified.
  4806. if( ctx->type.isVariable )
  4807. {
  4808. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  4809. ctx->type.dataType.MakeReadOnly(false);
  4810. ctx->type.dataType.MakeHandle(true);
  4811. ctx->type.dataType.MakeReadOnly(true);
  4812. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  4813. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4814. {
  4815. ctx->bc.Instr(asBC_PopPtr);
  4816. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4817. ctx->type.dataType.MakeReference(true);
  4818. }
  4819. else if( ctx->type.dataType.IsReference() )
  4820. {
  4821. ctx->bc.Instr(asBC_RDSPtr);
  4822. ctx->type.dataType.MakeReference(false);
  4823. }
  4824. }
  4825. else
  4826. {
  4827. int offset = AllocateVariable(dt, true);
  4828. if( ctx->type.dataType.IsReference() )
  4829. ctx->bc.Instr(asBC_RDSPtr);
  4830. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4831. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  4832. ctx->bc.Instr(asBC_PopPtr);
  4833. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4834. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4835. if( to.IsReference() )
  4836. dt.MakeReference(true);
  4837. else
  4838. ctx->bc.Instr(asBC_RDSPtr);
  4839. ctx->type.SetVariable(dt, offset, true);
  4840. }
  4841. }
  4842. else
  4843. ctx->type.dataType = dt;
  4844. // When this conversion is done the expression is no longer an lvalue
  4845. ctx->type.isLValue = false;
  4846. }
  4847. }
  4848. if( ctx->type.dataType.IsObjectHandle() )
  4849. {
  4850. // A handle to non-const can be converted to a
  4851. // handle to const, but not the other way
  4852. if( to.IsHandleToConst() )
  4853. ctx->type.dataType.MakeHandleToConst(true);
  4854. // A const handle can be converted to a non-const
  4855. // handle and vice versa as the handle is just a value
  4856. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4857. }
  4858. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4859. {
  4860. if( generateCode )
  4861. {
  4862. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4863. // If the input type is a handle, then a simple ref copy is enough
  4864. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4865. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  4866. // If the input type is read-only we'll need to temporarily
  4867. // remove this constness, otherwise the assignment will fail
  4868. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4869. ctx->type.dataType.MakeReadOnly(false);
  4870. // If the object already is a temporary variable, then the copy
  4871. // doesn't have to be made as it is already a unique object
  4872. PrepareTemporaryObject(node, ctx);
  4873. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4874. ctx->type.isExplicitHandle = isExplicitHandle;
  4875. }
  4876. // A non-reference can be converted to a reference,
  4877. // by putting the value in a temporary variable
  4878. ctx->type.dataType.MakeReference(true);
  4879. // Since it is a new temporary variable it doesn't have to be const
  4880. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4881. }
  4882. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  4883. {
  4884. Dereference(ctx, generateCode);
  4885. }
  4886. }
  4887. else // if( !to.IsObjectHandle() )
  4888. {
  4889. if( !to.IsReference() )
  4890. {
  4891. // reference to handle -> object
  4892. // handle -> object
  4893. // reference -> object
  4894. // An implicit handle can be converted to an object by adding a check for null pointer
  4895. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4896. {
  4897. if( generateCode )
  4898. {
  4899. if( ctx->type.dataType.IsReference() )
  4900. {
  4901. // The pointer on the stack refers to the handle
  4902. ctx->bc.Instr(asBC_ChkRefS);
  4903. }
  4904. else
  4905. {
  4906. // The pointer on the stack refers to the object
  4907. ctx->bc.Instr(asBC_CHKREF);
  4908. }
  4909. }
  4910. ctx->type.dataType.MakeHandle(false);
  4911. }
  4912. // A const object can be converted to a non-const object through a copy
  4913. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  4914. allowObjectConstruct )
  4915. {
  4916. // Does the object type allow a copy to be made?
  4917. if( ctx->type.dataType.CanBeCopied() )
  4918. {
  4919. if( generateCode )
  4920. {
  4921. // Make a temporary object with the copy
  4922. PrepareTemporaryObject(node, ctx);
  4923. }
  4924. // In case the object was already in a temporary variable, then the function
  4925. // didn't really do anything so we need to remove the constness here
  4926. ctx->type.dataType.MakeReadOnly(false);
  4927. // Add the cost for the copy
  4928. cost += asCC_TO_OBJECT_CONV;
  4929. }
  4930. }
  4931. if( ctx->type.dataType.IsReference() )
  4932. {
  4933. // This may look strange, but a value type allocated on the stack is already
  4934. // correct, so nothing should be done other than remove the mark as reference.
  4935. // For types allocated on the heap, it is necessary to dereference the pointer
  4936. // that is currently on the stack
  4937. if( IsVariableOnHeap(ctx->type.stackOffset) )
  4938. Dereference(ctx, generateCode);
  4939. else
  4940. ctx->type.dataType.MakeReference(false);
  4941. }
  4942. // A non-const object can be converted to a const object directly
  4943. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4944. {
  4945. ctx->type.dataType.MakeReadOnly(true);
  4946. }
  4947. }
  4948. else // if( to.IsReference() )
  4949. {
  4950. // reference to handle -> reference
  4951. // handle -> reference
  4952. // object -> reference
  4953. if( ctx->type.dataType.IsReference() )
  4954. {
  4955. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4956. {
  4957. // ASHANDLE objects are really value types, so explicit handle can be removed
  4958. ctx->type.isExplicitHandle = false;
  4959. ctx->type.dataType.MakeHandle(false);
  4960. }
  4961. // A reference to a handle can be converted to a reference to an object
  4962. // by first reading the address, then verifying that it is not null
  4963. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4964. {
  4965. ctx->type.dataType.MakeHandle(false);
  4966. if( generateCode )
  4967. ctx->bc.Instr(asBC_ChkRefS);
  4968. }
  4969. // A reference to a non-const can be converted to a reference to a const
  4970. if( to.IsReadOnly() )
  4971. ctx->type.dataType.MakeReadOnly(true);
  4972. else if( ctx->type.dataType.IsReadOnly() )
  4973. {
  4974. // A reference to a const can be converted to a reference to a
  4975. // non-const by copying the object to a temporary variable
  4976. ctx->type.dataType.MakeReadOnly(false);
  4977. if( generateCode )
  4978. {
  4979. // If the object already is a temporary variable, then the copy
  4980. // doesn't have to be made as it is already a unique object
  4981. PrepareTemporaryObject(node, ctx);
  4982. }
  4983. // Add the cost for the copy
  4984. cost += asCC_TO_OBJECT_CONV;
  4985. }
  4986. }
  4987. else // if( !ctx->type.dataType.IsReference() )
  4988. {
  4989. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  4990. if( ctx->type.dataType.IsObjectHandle() )
  4991. {
  4992. bool readOnly = false;
  4993. if( ctx->type.dataType.IsHandleToConst() )
  4994. readOnly = true;
  4995. if( generateCode )
  4996. {
  4997. if( ctx->type.isVariable )
  4998. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4999. else
  5000. ctx->bc.Instr(asBC_CHKREF);
  5001. }
  5002. ctx->type.dataType.MakeHandle(false);
  5003. ctx->type.dataType.MakeReference(true);
  5004. // Make sure a handle to const isn't converted to non-const reference
  5005. if( readOnly )
  5006. ctx->type.dataType.MakeReadOnly(true);
  5007. }
  5008. else
  5009. {
  5010. // A value type allocated on the stack is differentiated
  5011. // by it not being a reference. But it can be handled as
  5012. // reference by pushing the pointer on the stack
  5013. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  5014. (ctx->type.isVariable || ctx->type.isTemporary) &&
  5015. !IsVariableOnHeap(ctx->type.stackOffset) )
  5016. {
  5017. // Actually the pointer is already pushed on the stack in
  5018. // CompileVariableAccess, so we don't need to do anything else
  5019. }
  5020. else if( generateCode )
  5021. {
  5022. // A non-reference can be converted to a reference,
  5023. // by putting the value in a temporary variable
  5024. // If the input type is read-only we'll need to temporarily
  5025. // remove this constness, otherwise the assignment will fail
  5026. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5027. ctx->type.dataType.MakeReadOnly(false);
  5028. // If the object already is a temporary variable, then the copy
  5029. // doesn't have to be made as it is already a unique object
  5030. PrepareTemporaryObject(node, ctx);
  5031. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5032. // Add the cost for the copy
  5033. cost += asCC_TO_OBJECT_CONV;
  5034. }
  5035. // This may look strange as the conversion was to make the expression a reference
  5036. // but a value type allocated on the stack is a reference even without the type
  5037. // being marked as such.
  5038. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  5039. }
  5040. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  5041. // Since it is a new temporary variable it doesn't have to be const
  5042. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5043. }
  5044. }
  5045. }
  5046. return cost;
  5047. }
  5048. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  5049. {
  5050. // Reference types currently don't allow implicit conversion from primitive to object
  5051. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  5052. asCObjectType *objType = to.GetObjectType();
  5053. asASSERT( objType );
  5054. if( !objType || (objType->flags & asOBJ_REF) )
  5055. return asCC_NO_CONV;
  5056. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  5057. asCArray<int> funcs;
  5058. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  5059. {
  5060. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  5061. if( func->parameterTypes.GetLength() == 1 &&
  5062. func->parameterTypes[0].IsPrimitive() &&
  5063. !(func->inOutFlags[0] & asTM_OUTREF) )
  5064. {
  5065. funcs.PushLast(func->id);
  5066. }
  5067. }
  5068. if( funcs.GetLength() == 0 )
  5069. return asCC_NO_CONV;
  5070. // Check if it is possible to choose a best match
  5071. asSExprContext arg(engine);
  5072. arg.type = ctx->type;
  5073. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  5074. asCArray<asSExprContext*> args;
  5075. args.PushLast(&arg);
  5076. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, objType, false, true, false);
  5077. if( funcs.GetLength() != 1 )
  5078. return asCC_NO_CONV;
  5079. if( !generateCode )
  5080. {
  5081. ctx->type.Set(to);
  5082. return cost;
  5083. }
  5084. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  5085. bool onHeap = true;
  5086. // Value types and script types are allocated through the constructor
  5087. asCTypeInfo tempObj;
  5088. tempObj.dataType = to;
  5089. tempObj.stackOffset = (short)AllocateVariable(to, true);
  5090. tempObj.dataType.MakeReference(true);
  5091. tempObj.isTemporary = true;
  5092. tempObj.isVariable = true;
  5093. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5094. // Push the address of the object on the stack
  5095. if( onHeap )
  5096. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5097. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  5098. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  5099. if( !(objType->flags & asOBJ_REF) )
  5100. {
  5101. // If the object is allocated on the stack, then call the constructor as a normal function
  5102. if( onHeap )
  5103. {
  5104. int offset = 0;
  5105. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5106. for( asUINT n = 0; n < args.GetLength(); n++ )
  5107. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  5108. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5109. }
  5110. else
  5111. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5112. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  5113. // Add tag that the object has been initialized
  5114. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  5115. // The constructor doesn't return anything,
  5116. // so we have to manually inform the type of
  5117. // the return value
  5118. ctx->type = tempObj;
  5119. if( !onHeap )
  5120. ctx->type.dataType.MakeReference(false);
  5121. // Push the address of the object on the stack again
  5122. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5123. }
  5124. else
  5125. {
  5126. asASSERT( objType->flags & asOBJ_SCOPED );
  5127. // Call the factory to create the reference type
  5128. PerformFunctionCall(funcs[0], ctx, false, &args);
  5129. }
  5130. return cost;
  5131. }
  5132. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  5133. {
  5134. asASSERT(from->type.isConstant);
  5135. // TODO: node should be the node of the value that is
  5136. // converted (not the operator that provokes the implicit
  5137. // conversion)
  5138. // If the base type is correct there is no more to do
  5139. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  5140. // References cannot be constants
  5141. if( from->type.dataType.IsReference() ) return;
  5142. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5143. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5144. {
  5145. if( from->type.dataType.IsFloatType() ||
  5146. from->type.dataType.IsDoubleType() ||
  5147. from->type.dataType.IsUnsignedType() ||
  5148. from->type.dataType.IsIntegerType() )
  5149. {
  5150. // Transform the value
  5151. // Float constants can be implicitly converted to int
  5152. if( from->type.dataType.IsFloatType() )
  5153. {
  5154. float fc = from->type.floatValue;
  5155. int ic = int(fc);
  5156. if( float(ic) != fc )
  5157. {
  5158. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5159. }
  5160. from->type.intValue = ic;
  5161. }
  5162. // Double constants can be implicitly converted to int
  5163. else if( from->type.dataType.IsDoubleType() )
  5164. {
  5165. double fc = from->type.doubleValue;
  5166. int ic = int(fc);
  5167. if( double(ic) != fc )
  5168. {
  5169. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5170. }
  5171. from->type.intValue = ic;
  5172. }
  5173. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5174. {
  5175. // Verify that it is possible to convert to signed without getting negative
  5176. if( from->type.intValue < 0 )
  5177. {
  5178. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5179. }
  5180. // Convert to 32bit
  5181. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5182. from->type.intValue = from->type.byteValue;
  5183. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5184. from->type.intValue = from->type.wordValue;
  5185. }
  5186. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5187. {
  5188. // Convert to 32bit
  5189. from->type.intValue = int(from->type.qwordValue);
  5190. }
  5191. else if( from->type.dataType.IsIntegerType() &&
  5192. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5193. {
  5194. // Convert to 32bit
  5195. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5196. from->type.intValue = (signed char)from->type.byteValue;
  5197. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5198. from->type.intValue = (short)from->type.wordValue;
  5199. }
  5200. // Set the resulting type
  5201. if( to.IsEnumType() )
  5202. from->type.dataType = to;
  5203. else
  5204. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  5205. }
  5206. // Check if a downsize is necessary
  5207. if( to.IsIntegerType() &&
  5208. from->type.dataType.IsIntegerType() &&
  5209. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5210. {
  5211. // Verify if it is possible
  5212. if( to.GetSizeInMemoryBytes() == 1 )
  5213. {
  5214. if( char(from->type.intValue) != from->type.intValue )
  5215. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5216. from->type.byteValue = char(from->type.intValue);
  5217. }
  5218. else if( to.GetSizeInMemoryBytes() == 2 )
  5219. {
  5220. if( short(from->type.intValue) != from->type.intValue )
  5221. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5222. from->type.wordValue = short(from->type.intValue);
  5223. }
  5224. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5225. }
  5226. }
  5227. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5228. {
  5229. // Float constants can be implicitly converted to int
  5230. if( from->type.dataType.IsFloatType() )
  5231. {
  5232. float fc = from->type.floatValue;
  5233. asINT64 ic = asINT64(fc);
  5234. if( float(ic) != fc )
  5235. {
  5236. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5237. }
  5238. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5239. from->type.qwordValue = ic;
  5240. }
  5241. // Double constants can be implicitly converted to int
  5242. else if( from->type.dataType.IsDoubleType() )
  5243. {
  5244. double fc = from->type.doubleValue;
  5245. asINT64 ic = asINT64(fc);
  5246. if( double(ic) != fc )
  5247. {
  5248. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5249. }
  5250. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5251. from->type.qwordValue = ic;
  5252. }
  5253. else if( from->type.dataType.IsUnsignedType() )
  5254. {
  5255. // Convert to 64bit
  5256. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5257. from->type.qwordValue = from->type.byteValue;
  5258. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5259. from->type.qwordValue = from->type.wordValue;
  5260. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5261. from->type.qwordValue = from->type.dwordValue;
  5262. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  5263. {
  5264. if( asINT64(from->type.qwordValue) < 0 )
  5265. {
  5266. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5267. }
  5268. }
  5269. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5270. }
  5271. else if( from->type.dataType.IsIntegerType() )
  5272. {
  5273. // Convert to 64bit
  5274. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5275. from->type.qwordValue = (signed char)from->type.byteValue;
  5276. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5277. from->type.qwordValue = (short)from->type.wordValue;
  5278. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5279. from->type.qwordValue = from->type.intValue;
  5280. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5281. }
  5282. }
  5283. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5284. {
  5285. if( from->type.dataType.IsFloatType() )
  5286. {
  5287. float fc = from->type.floatValue;
  5288. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  5289. // To maintain a consistent behaviour across compilers we convert to int first.
  5290. asUINT uic = asUINT(int(fc));
  5291. if( float(uic) != fc )
  5292. {
  5293. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5294. }
  5295. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5296. from->type.intValue = uic;
  5297. // Try once more, in case of a smaller type
  5298. ImplicitConversionConstant(from, to, node, convType);
  5299. }
  5300. else if( from->type.dataType.IsDoubleType() )
  5301. {
  5302. double fc = from->type.doubleValue;
  5303. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  5304. // To maintain a consistent behaviour across compilers we convert to int first.
  5305. asUINT uic = asUINT(int(fc));
  5306. if( double(uic) != fc )
  5307. {
  5308. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5309. }
  5310. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5311. from->type.intValue = uic;
  5312. // Try once more, in case of a smaller type
  5313. ImplicitConversionConstant(from, to, node, convType);
  5314. }
  5315. else if( from->type.dataType.IsIntegerType() )
  5316. {
  5317. // Verify that it is possible to convert to unsigned without loosing negative
  5318. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) ||
  5319. (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) )
  5320. {
  5321. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5322. }
  5323. // Check if any data is lost
  5324. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF )
  5325. {
  5326. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5327. }
  5328. // Convert to 32bit
  5329. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5330. from->type.intValue = (signed char)from->type.byteValue;
  5331. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5332. from->type.intValue = (short)from->type.wordValue;
  5333. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5334. // Try once more, in case of a smaller type
  5335. ImplicitConversionConstant(from, to, node, convType);
  5336. }
  5337. else if( from->type.dataType.IsUnsignedType() &&
  5338. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5339. {
  5340. // Convert to 32bit
  5341. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5342. from->type.dwordValue = from->type.byteValue;
  5343. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5344. from->type.dwordValue = from->type.wordValue;
  5345. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5346. // Try once more, in case of a smaller type
  5347. ImplicitConversionConstant(from, to, node, convType);
  5348. }
  5349. else if( from->type.dataType.IsUnsignedType() &&
  5350. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5351. {
  5352. // Verify if it is possible
  5353. if( to.GetSizeInMemoryBytes() == 1 )
  5354. {
  5355. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  5356. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5357. from->type.byteValue = asBYTE(from->type.dwordValue);
  5358. }
  5359. else if( to.GetSizeInMemoryBytes() == 2 )
  5360. {
  5361. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  5362. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5363. from->type.wordValue = asWORD(from->type.dwordValue);
  5364. }
  5365. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5366. }
  5367. }
  5368. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5369. {
  5370. if( from->type.dataType.IsFloatType() )
  5371. {
  5372. float fc = from->type.floatValue;
  5373. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5374. asQWORD uic = asQWORD(asINT64(fc));
  5375. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5376. // MSVC6 doesn't support this conversion
  5377. if( float(uic) != fc )
  5378. {
  5379. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5380. }
  5381. #endif
  5382. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5383. from->type.qwordValue = uic;
  5384. }
  5385. else if( from->type.dataType.IsDoubleType() )
  5386. {
  5387. double fc = from->type.doubleValue;
  5388. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5389. asQWORD uic = asQWORD(asINT64(fc));
  5390. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5391. // MSVC6 doesn't support this conversion
  5392. if( double(uic) != fc )
  5393. {
  5394. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5395. }
  5396. #endif
  5397. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5398. from->type.qwordValue = uic;
  5399. }
  5400. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5401. {
  5402. // Convert to 64bit
  5403. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5404. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  5405. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5406. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  5407. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5408. from->type.qwordValue = (asINT64)from->type.intValue;
  5409. // Verify that it is possible to convert to unsigned without loosing negative
  5410. if( asINT64(from->type.qwordValue) < 0 )
  5411. {
  5412. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5413. }
  5414. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5415. }
  5416. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5417. {
  5418. // Verify that it is possible to convert to unsigned without loosing negative
  5419. if( asINT64(from->type.qwordValue) < 0 )
  5420. {
  5421. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5422. }
  5423. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5424. }
  5425. else if( from->type.dataType.IsUnsignedType() )
  5426. {
  5427. // Convert to 64bit
  5428. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5429. from->type.qwordValue = from->type.byteValue;
  5430. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5431. from->type.qwordValue = from->type.wordValue;
  5432. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5433. from->type.qwordValue = from->type.dwordValue;
  5434. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5435. }
  5436. }
  5437. else if( to.IsFloatType() )
  5438. {
  5439. if( from->type.dataType.IsDoubleType() )
  5440. {
  5441. double ic = from->type.doubleValue;
  5442. float fc = float(ic);
  5443. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5444. from->type.floatValue = fc;
  5445. }
  5446. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5447. {
  5448. // Must properly convert value in case the from value is smaller
  5449. int ic;
  5450. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5451. ic = (signed char)from->type.byteValue;
  5452. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5453. ic = (short)from->type.wordValue;
  5454. else
  5455. ic = from->type.intValue;
  5456. float fc = float(ic);
  5457. if( int(fc) != ic )
  5458. {
  5459. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5460. }
  5461. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5462. from->type.floatValue = fc;
  5463. }
  5464. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5465. {
  5466. float fc = float(asINT64(from->type.qwordValue));
  5467. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5468. {
  5469. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5470. }
  5471. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5472. from->type.floatValue = fc;
  5473. }
  5474. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5475. {
  5476. // Must properly convert value in case the from value is smaller
  5477. unsigned int uic;
  5478. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5479. uic = from->type.byteValue;
  5480. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5481. uic = from->type.wordValue;
  5482. else
  5483. uic = from->type.dwordValue;
  5484. float fc = float(uic);
  5485. if( (unsigned int)(fc) != uic )
  5486. {
  5487. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5488. }
  5489. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5490. from->type.floatValue = fc;
  5491. }
  5492. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5493. {
  5494. float fc = float((asINT64)from->type.qwordValue);
  5495. if( asQWORD(fc) != from->type.qwordValue )
  5496. {
  5497. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5498. }
  5499. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5500. from->type.floatValue = fc;
  5501. }
  5502. }
  5503. else if( to.IsDoubleType() )
  5504. {
  5505. if( from->type.dataType.IsFloatType() )
  5506. {
  5507. float ic = from->type.floatValue;
  5508. double fc = double(ic);
  5509. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5510. from->type.doubleValue = fc;
  5511. }
  5512. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5513. {
  5514. // Must properly convert value in case the from value is smaller
  5515. int ic;
  5516. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5517. ic = (signed char)from->type.byteValue;
  5518. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5519. ic = (short)from->type.wordValue;
  5520. else
  5521. ic = from->type.intValue;
  5522. double fc = double(ic);
  5523. if( int(fc) != ic )
  5524. {
  5525. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5526. }
  5527. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5528. from->type.doubleValue = fc;
  5529. }
  5530. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5531. {
  5532. double fc = double(asINT64(from->type.qwordValue));
  5533. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5534. {
  5535. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5536. }
  5537. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5538. from->type.doubleValue = fc;
  5539. }
  5540. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5541. {
  5542. // Must properly convert value in case the from value is smaller
  5543. unsigned int uic;
  5544. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5545. uic = from->type.byteValue;
  5546. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5547. uic = from->type.wordValue;
  5548. else
  5549. uic = from->type.dwordValue;
  5550. double fc = double(uic);
  5551. if( (unsigned int)(fc) != uic )
  5552. {
  5553. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5554. }
  5555. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5556. from->type.doubleValue = fc;
  5557. }
  5558. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5559. {
  5560. double fc = double((asINT64)from->type.qwordValue);
  5561. if( asQWORD(fc) != from->type.qwordValue )
  5562. {
  5563. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5564. }
  5565. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5566. from->type.doubleValue = fc;
  5567. }
  5568. }
  5569. }
  5570. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  5571. {
  5572. // Don't allow any operators on expressions that take address of class method
  5573. // If methodName is set but the type is not an object, then it is a global function
  5574. if( lctx->methodName != "" || rctx->IsClassMethod() )
  5575. {
  5576. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  5577. return -1;
  5578. }
  5579. // Implicit handle types should always be treated as handles in assignments
  5580. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5581. {
  5582. lctx->type.dataType.MakeHandle(true);
  5583. lctx->type.isExplicitHandle = true;
  5584. }
  5585. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  5586. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  5587. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  5588. !lctx->type.dataType.GetBehaviour()->copy)
  5589. lctx->type.isExplicitHandle = true;
  5590. // If the left hand expression is a property accessor, then that should be used
  5591. // to do the assignment instead of the ordinary operator. The exception is when
  5592. // the property accessor is for a handle property, and the operation is a value
  5593. // assignment.
  5594. if( (lctx->property_get || lctx->property_set) &&
  5595. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  5596. {
  5597. if( op != ttAssignment )
  5598. {
  5599. // TODO: getset: We may actually be able to support this, if we can
  5600. // guarantee that the object reference will stay valid
  5601. // between the calls to the get and set accessors.
  5602. // Process the property to free the memory
  5603. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5604. // Compound assignments are not allowed for properties
  5605. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  5606. return -1;
  5607. }
  5608. // It is not allowed to do a handle assignment on a property
  5609. // accessor that doesn't take a handle in the set accessor.
  5610. if( lctx->property_set && lctx->type.isExplicitHandle )
  5611. {
  5612. // set_opIndex has 2 arguments, where as normal setters have only 1
  5613. asCArray<asCDataType>& parameterTypes =
  5614. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  5615. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  5616. {
  5617. // Process the property to free the memory
  5618. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5619. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  5620. return -1;
  5621. }
  5622. }
  5623. MergeExprBytecodeAndType(ctx, lctx);
  5624. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  5625. }
  5626. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5627. {
  5628. // Get the handle to the object that will be used for the value assignment
  5629. ProcessPropertyGetAccessor(lctx, opNode);
  5630. }
  5631. if( lctx->type.dataType.IsPrimitive() )
  5632. {
  5633. if( !lctx->type.isLValue )
  5634. {
  5635. Error(TXT_NOT_LVALUE, lexpr);
  5636. return -1;
  5637. }
  5638. if( op != ttAssignment )
  5639. {
  5640. // Compute the operator before the assignment
  5641. asCTypeInfo lvalue = lctx->type;
  5642. if( lctx->type.isTemporary && !lctx->type.isVariable )
  5643. {
  5644. // The temporary variable must not be freed until the
  5645. // assignment has been performed. lvalue still holds
  5646. // the information about the temporary variable
  5647. lctx->type.isTemporary = false;
  5648. }
  5649. asSExprContext o(engine);
  5650. CompileOperator(opNode, lctx, rctx, &o);
  5651. MergeExprBytecode(rctx, &o);
  5652. rctx->type = o.type;
  5653. // Convert the rvalue to the right type and validate it
  5654. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  5655. MergeExprBytecode(ctx, rctx);
  5656. lctx->type = lvalue;
  5657. // The lvalue continues the same, either it was a variable, or a reference in the register
  5658. }
  5659. else
  5660. {
  5661. // Convert the rvalue to the right type and validate it
  5662. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  5663. MergeExprBytecode(ctx, rctx);
  5664. MergeExprBytecode(ctx, lctx);
  5665. }
  5666. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5667. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5668. ctx->type = lctx->type;
  5669. }
  5670. else if( lctx->type.isExplicitHandle )
  5671. {
  5672. if( !lctx->type.isLValue )
  5673. {
  5674. Error(TXT_NOT_LVALUE, lexpr);
  5675. return -1;
  5676. }
  5677. // Object handles don't have any compound assignment operators
  5678. if( op != ttAssignment )
  5679. {
  5680. asCString str;
  5681. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5682. Error(str, lexpr);
  5683. return -1;
  5684. }
  5685. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5686. {
  5687. // The object is a value type but that should be treated as a handle
  5688. // Make sure the right hand value is a handle
  5689. if( !rctx->type.isExplicitHandle &&
  5690. !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  5691. {
  5692. // Function names can be considered handles already
  5693. if( rctx->methodName == "" )
  5694. {
  5695. asCDataType dt = rctx->type.dataType;
  5696. dt.MakeHandle(true);
  5697. dt.MakeReference(false);
  5698. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  5699. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5700. {
  5701. asCString str;
  5702. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5703. Error(str, rexpr);
  5704. return -1;
  5705. }
  5706. }
  5707. }
  5708. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5709. {
  5710. // An overloaded assignment operator was found (or a compilation error occured)
  5711. return 0;
  5712. }
  5713. // The object must implement the opAssign method
  5714. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  5715. return -1;
  5716. }
  5717. else
  5718. {
  5719. asCDataType dt = lctx->type.dataType;
  5720. dt.MakeReference(false);
  5721. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
  5722. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5723. {
  5724. asCString str;
  5725. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5726. Error(str, rexpr);
  5727. return -1;
  5728. }
  5729. MergeExprBytecode(ctx, rctx);
  5730. MergeExprBytecode(ctx, lctx);
  5731. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5732. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5733. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5734. ctx->type = lctx->type;
  5735. // After the handle assignment the original handle is left on the stack
  5736. ctx->type.dataType.MakeReference(false);
  5737. }
  5738. }
  5739. else // if( lctx->type.dataType.IsObject() )
  5740. {
  5741. // An ASHANDLE type must not allow a value assignment, as
  5742. // the opAssign operator is used for the handle assignment
  5743. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5744. {
  5745. asCString str;
  5746. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5747. Error(str, lexpr);
  5748. return -1;
  5749. }
  5750. // The lvalue reference may be marked as a temporary, if for example
  5751. // it was originated as a handle returned from a function. In such
  5752. // cases it must be possible to assign values to it anyway.
  5753. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5754. {
  5755. // Convert the handle to a object reference
  5756. asCDataType to;
  5757. to = lctx->type.dataType;
  5758. to.MakeHandle(false);
  5759. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  5760. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  5761. }
  5762. // Check for overloaded assignment operator
  5763. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5764. {
  5765. // An overloaded assignment operator was found (or a compilation error occured)
  5766. return 0;
  5767. }
  5768. // No registered operator was found. In case the operation is a direct
  5769. // assignment and the rvalue is the same type as the lvalue, then we can
  5770. // still use the byte-for-byte copy to do the assignment
  5771. if( op != ttAssignment )
  5772. {
  5773. asCString str;
  5774. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5775. Error(str, lexpr);
  5776. return -1;
  5777. }
  5778. // If the left hand expression is simple, i.e. without any
  5779. // function calls or allocations of memory, then we can avoid
  5780. // doing a copy of the right hand expression (done by PrepareArgument).
  5781. // Instead the reference to the value can be placed directly on the
  5782. // stack.
  5783. //
  5784. // This optimization should only be done for value types, where
  5785. // the application developer is responsible for making the
  5786. // implementation safe against unwanted destruction of the input
  5787. // reference before the time.
  5788. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  5789. // Implicitly convert the rvalue to the type of the lvalue
  5790. bool needConversion = false;
  5791. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5792. needConversion = true;
  5793. if( !simpleExpr || needConversion )
  5794. {
  5795. asCDataType dt = lctx->type.dataType;
  5796. dt.MakeReference(true);
  5797. dt.MakeReadOnly(true);
  5798. PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  5799. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5800. {
  5801. asCString str;
  5802. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5803. Error(str, rexpr);
  5804. return -1;
  5805. }
  5806. }
  5807. else
  5808. {
  5809. // Process any property accessor first, before placing the final reference on the stack
  5810. ProcessPropertyGetAccessor(rctx, rexpr);
  5811. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  5812. rctx->bc.Instr(asBC_RDSPtr);
  5813. }
  5814. MergeExprBytecode(ctx, rctx);
  5815. MergeExprBytecode(ctx, lctx);
  5816. if( !simpleExpr || needConversion )
  5817. {
  5818. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  5819. {
  5820. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  5821. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  5822. // as the value allocated on the stack is guaranteed to be safe.
  5823. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  5824. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  5825. else
  5826. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5827. }
  5828. }
  5829. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5830. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5831. ctx->type = lctx->type;
  5832. }
  5833. return 0;
  5834. }
  5835. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  5836. {
  5837. asCScriptNode *lexpr = expr->firstChild;
  5838. if( lexpr->next )
  5839. {
  5840. // Compile the two expression terms
  5841. asSExprContext lctx(engine), rctx(engine);
  5842. int rr = CompileAssignment(lexpr->next->next, &rctx);
  5843. int lr = CompileCondition(lexpr, &lctx);
  5844. if( lr >= 0 && rr >= 0 )
  5845. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  5846. // Since the operands failed, the assignment was not computed
  5847. ctx->type.SetDummy();
  5848. return -1;
  5849. }
  5850. return CompileCondition(lexpr, ctx);
  5851. }
  5852. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  5853. {
  5854. asCTypeInfo ctype;
  5855. // Compile the conditional expression
  5856. asCScriptNode *cexpr = expr->firstChild;
  5857. if( cexpr->next )
  5858. {
  5859. //-------------------------------
  5860. // Compile the condition
  5861. asSExprContext e(engine);
  5862. int r = CompileExpression(cexpr, &e);
  5863. if( r < 0 )
  5864. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5865. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  5866. {
  5867. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  5868. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5869. }
  5870. ctype = e.type;
  5871. ProcessPropertyGetAccessor(&e, cexpr);
  5872. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  5873. ProcessDeferredParams(&e);
  5874. //-------------------------------
  5875. // Compile the left expression
  5876. asSExprContext le(engine);
  5877. int lr = CompileAssignment(cexpr->next, &le);
  5878. //-------------------------------
  5879. // Compile the right expression
  5880. asSExprContext re(engine);
  5881. int rr = CompileAssignment(cexpr->next->next, &re);
  5882. if( lr >= 0 && rr >= 0 )
  5883. {
  5884. // Don't allow any operators on expressions that take address of class method
  5885. if( le.IsClassMethod() || re.IsClassMethod() )
  5886. {
  5887. Error(TXT_INVALID_OP_ON_METHOD, expr);
  5888. return -1;
  5889. }
  5890. ProcessPropertyGetAccessor(&le, cexpr->next);
  5891. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  5892. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  5893. // Allow a 0 or null in the first case to be implicitly converted to the second type
  5894. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsIntegerType() )
  5895. {
  5896. asCDataType to = re.type.dataType;
  5897. to.MakeReference(false);
  5898. to.MakeReadOnly(true);
  5899. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5900. }
  5901. else if( le.type.IsNullConstant() )
  5902. {
  5903. asCDataType to = re.type.dataType;
  5904. to.MakeHandle(true);
  5905. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5906. }
  5907. //---------------------------------
  5908. // Output the byte code
  5909. int afterLabel = nextLabel++;
  5910. int elseLabel = nextLabel++;
  5911. // If left expression is void, then we don't need to store the result
  5912. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  5913. {
  5914. // Put the code for the condition expression on the output
  5915. MergeExprBytecode(ctx, &e);
  5916. // Added the branch decision
  5917. ctx->type = e.type;
  5918. ConvertToVariable(ctx);
  5919. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5920. ctx->bc.Instr(asBC_ClrHi);
  5921. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5922. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5923. // Add the left expression
  5924. MergeExprBytecode(ctx, &le);
  5925. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5926. // Add the right expression
  5927. ctx->bc.Label((short)elseLabel);
  5928. MergeExprBytecode(ctx, &re);
  5929. ctx->bc.Label((short)afterLabel);
  5930. // Make sure both expressions have the same type
  5931. if( le.type.dataType != re.type.dataType )
  5932. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5933. // Set the type of the result
  5934. ctx->type = le.type;
  5935. }
  5936. else
  5937. {
  5938. // Allocate temporary variable and copy the result to that one
  5939. asCTypeInfo temp;
  5940. temp = le.type;
  5941. temp.dataType.MakeReference(false);
  5942. temp.dataType.MakeReadOnly(false);
  5943. // Make sure the variable isn't used in any of the expressions,
  5944. // as it would be overwritten which may cause crashes or less visible bugs
  5945. int l = int(reservedVariables.GetLength());
  5946. e.bc.GetVarsUsed(reservedVariables);
  5947. le.bc.GetVarsUsed(reservedVariables);
  5948. re.bc.GetVarsUsed(reservedVariables);
  5949. int offset = AllocateVariable(temp.dataType, true, false);
  5950. reservedVariables.SetLength(l);
  5951. temp.SetVariable(temp.dataType, offset, true);
  5952. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  5953. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  5954. // Put the code for the condition expression on the output
  5955. MergeExprBytecode(ctx, &e);
  5956. // Add the branch decision
  5957. ctx->type = e.type;
  5958. ConvertToVariable(ctx);
  5959. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5960. ctx->bc.Instr(asBC_ClrHi);
  5961. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5962. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5963. // Assign the result of the left expression to the temporary variable
  5964. asCTypeInfo rtemp;
  5965. rtemp = temp;
  5966. if( rtemp.dataType.IsObjectHandle() )
  5967. rtemp.isExplicitHandle = true;
  5968. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  5969. MergeExprBytecode(ctx, &le);
  5970. if( !rtemp.dataType.IsPrimitive() )
  5971. {
  5972. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5973. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5974. }
  5975. asCTypeInfo result;
  5976. result = rtemp;
  5977. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  5978. if( !result.dataType.IsPrimitive() )
  5979. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5980. // Release the old temporary variable
  5981. ReleaseTemporaryVariable(le.type, &ctx->bc);
  5982. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5983. // Start of the right expression
  5984. ctx->bc.Label((short)elseLabel);
  5985. // Copy the result to the same temporary variable
  5986. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  5987. MergeExprBytecode(ctx, &re);
  5988. if( !rtemp.dataType.IsPrimitive() )
  5989. {
  5990. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5991. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5992. }
  5993. result = rtemp;
  5994. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  5995. if( !result.dataType.IsPrimitive() )
  5996. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5997. // Release the old temporary variable
  5998. ReleaseTemporaryVariable(re.type, &ctx->bc);
  5999. ctx->bc.Label((short)afterLabel);
  6000. // Make sure both expressions have the same type
  6001. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  6002. Error(TXT_BOTH_MUST_BE_SAME, expr);
  6003. // Set the temporary variable as output
  6004. ctx->type = rtemp;
  6005. ctx->type.isExplicitHandle = isExplicitHandle;
  6006. if( !ctx->type.dataType.IsPrimitive() )
  6007. {
  6008. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6009. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  6010. }
  6011. // Make sure the output isn't marked as being a literal constant
  6012. ctx->type.isConstant = false;
  6013. }
  6014. }
  6015. else
  6016. {
  6017. ctx->type.SetDummy();
  6018. return -1;
  6019. }
  6020. }
  6021. else
  6022. return CompileExpression(cexpr, ctx);
  6023. return 0;
  6024. }
  6025. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  6026. {
  6027. asASSERT(expr->nodeType == snExpression);
  6028. // Convert to polish post fix, i.e: a+b => ab+
  6029. // The algorithm that I've implemented here is similar to
  6030. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  6031. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  6032. // Count the nodes in order to preallocate the buffers
  6033. int count = 0;
  6034. asCScriptNode *node = expr->firstChild;
  6035. while( node )
  6036. {
  6037. count++;
  6038. node = node->next;
  6039. }
  6040. asCArray<asCScriptNode *> stack(count);
  6041. asCArray<asCScriptNode *> stack2(count);
  6042. node = expr->firstChild;
  6043. while( node )
  6044. {
  6045. int precedence = GetPrecedence(node);
  6046. while( stack.GetLength() > 0 &&
  6047. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  6048. stack2.PushLast(stack.PopLast());
  6049. stack.PushLast(node);
  6050. node = node->next;
  6051. }
  6052. while( stack.GetLength() > 0 )
  6053. stack2.PushLast(stack.PopLast());
  6054. // Compile the postfix formatted expression
  6055. return CompilePostFixExpression(&stack2, ctx);
  6056. }
  6057. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  6058. {
  6059. // Shouldn't send any byte code
  6060. asASSERT(ctx->bc.GetLastInstr() == -1);
  6061. // Set the context to a dummy type to avoid further
  6062. // errors in case the expression fails to compile
  6063. ctx->type.SetDummy();
  6064. // Evaluate the operands and operators
  6065. asCArray<asSExprContext*> free;
  6066. asCArray<asSExprContext*> expr;
  6067. int ret = 0;
  6068. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  6069. {
  6070. asCScriptNode *node = (*postfix)[n];
  6071. if( node->nodeType == snExprTerm )
  6072. {
  6073. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  6074. expr.PushLast(e);
  6075. e->exprNode = node;
  6076. ret = CompileExpressionTerm(node, e);
  6077. }
  6078. else
  6079. {
  6080. asSExprContext *r = expr.PopLast();
  6081. asSExprContext *l = expr.PopLast();
  6082. // Now compile the operator
  6083. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  6084. ret = CompileOperator(node, l, r, e);
  6085. expr.PushLast(e);
  6086. // Free the operands
  6087. l->Clear();
  6088. free.PushLast(l);
  6089. r->Clear();
  6090. free.PushLast(r);
  6091. }
  6092. }
  6093. if( ret == 0 )
  6094. {
  6095. asASSERT(expr.GetLength() == 1);
  6096. // The final result should be moved to the output context
  6097. MergeExprBytecodeAndType(ctx, expr[0]);
  6098. }
  6099. // Clean up
  6100. for( asUINT e = 0; e < expr.GetLength(); e++ )
  6101. asDELETE(expr[e], asSExprContext);
  6102. for( asUINT f = 0; f < free.GetLength(); f++ )
  6103. asDELETE(free[f], asSExprContext);
  6104. return ret;
  6105. }
  6106. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  6107. {
  6108. // Shouldn't send any byte code
  6109. asASSERT(ctx->bc.GetLastInstr() == -1);
  6110. // Set the type as a dummy by default, in case of any compiler errors
  6111. ctx->type.SetDummy();
  6112. // Compile the value node
  6113. asCScriptNode *vnode = node->firstChild;
  6114. while( vnode->nodeType != snExprValue )
  6115. vnode = vnode->next;
  6116. asSExprContext v(engine);
  6117. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  6118. // Compile post fix operators
  6119. asCScriptNode *pnode = vnode->next;
  6120. while( pnode )
  6121. {
  6122. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  6123. pnode = pnode->next;
  6124. }
  6125. // Compile pre fix operators
  6126. pnode = vnode->prev;
  6127. while( pnode )
  6128. {
  6129. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  6130. pnode = pnode->prev;
  6131. }
  6132. // Return the byte code and final type description
  6133. MergeExprBytecodeAndType(ctx, &v);
  6134. return 0;
  6135. }
  6136. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  6137. {
  6138. bool found = false;
  6139. // It is a local variable or parameter?
  6140. // This is not accessible by default arg expressions
  6141. sVariable *v = 0;
  6142. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  6143. v = variables->GetVariable(name.AddressOf());
  6144. if( v )
  6145. {
  6146. found = true;
  6147. if( v->isPureConstant )
  6148. ctx->type.SetConstantQW(v->type, v->constantValue);
  6149. else if( v->type.IsPrimitive() )
  6150. {
  6151. if( v->type.IsReference() )
  6152. {
  6153. // Copy the reference into the register
  6154. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  6155. ctx->bc.Instr(asBC_PopRPtr);
  6156. ctx->type.Set(v->type);
  6157. }
  6158. else
  6159. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6160. ctx->type.isLValue = true;
  6161. }
  6162. else
  6163. {
  6164. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  6165. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6166. // If the variable is allocated on the heap we have a reference,
  6167. // otherwise the actual object pointer is pushed on the stack.
  6168. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  6169. // Implicitly dereference handle parameters sent by reference
  6170. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  6171. ctx->bc.Instr(asBC_RDSPtr);
  6172. ctx->type.isLValue = true;
  6173. }
  6174. }
  6175. // Is it a class member?
  6176. // This is not accessible by default arg expressions
  6177. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  6178. {
  6179. if( name == THIS_TOKEN && !objType )
  6180. {
  6181. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  6182. // The object pointer is located at stack position 0
  6183. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6184. ctx->type.SetVariable(dt, 0, false);
  6185. ctx->type.dataType.MakeReference(true);
  6186. ctx->type.isLValue = true;
  6187. found = true;
  6188. }
  6189. if( !found )
  6190. {
  6191. // See if there are any matching property accessors
  6192. asSExprContext access(engine);
  6193. if( objType )
  6194. access.type.Set(asCDataType::CreateObject(objType, false));
  6195. else
  6196. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  6197. access.type.dataType.MakeReference(true);
  6198. int r = 0;
  6199. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6200. {
  6201. // This is an index access, check if there is a property accessor that takes an index arg
  6202. asSExprContext dummyArg(engine);
  6203. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  6204. }
  6205. if( r == 0 )
  6206. {
  6207. // Normal property access
  6208. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  6209. }
  6210. if( r < 0 ) return -1;
  6211. if( access.property_get || access.property_set )
  6212. {
  6213. if( !objType )
  6214. {
  6215. // Prepare the bytecode for the member access
  6216. // This is only done when accessing through the implicit this pointer
  6217. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6218. }
  6219. MergeExprBytecodeAndType(ctx, &access);
  6220. found = true;
  6221. }
  6222. }
  6223. if( !found )
  6224. {
  6225. asCDataType dt;
  6226. if( objType )
  6227. dt = asCDataType::CreateObject(objType, false);
  6228. else
  6229. dt = asCDataType::CreateObject(outFunc->objectType, false);
  6230. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  6231. if( prop )
  6232. {
  6233. if( !objType )
  6234. {
  6235. // The object pointer is located at stack position 0
  6236. // This is only done when accessing through the implicit this pointer
  6237. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6238. ctx->type.SetVariable(dt, 0, false);
  6239. ctx->type.dataType.MakeReference(true);
  6240. Dereference(ctx, true);
  6241. }
  6242. // TODO: This is the same as what is in CompileExpressionPostOp
  6243. // Put the offset on the stack
  6244. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  6245. if( prop->type.IsReference() )
  6246. ctx->bc.Instr(asBC_RDSPtr);
  6247. // Reference to primitive must be stored in the temp register
  6248. if( prop->type.IsPrimitive() )
  6249. {
  6250. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  6251. ctx->bc.Instr(asBC_PopRPtr);
  6252. }
  6253. // Set the new type (keeping info about temp variable)
  6254. ctx->type.dataType = prop->type;
  6255. ctx->type.dataType.MakeReference(true);
  6256. ctx->type.isVariable = false;
  6257. ctx->type.isLValue = true;
  6258. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  6259. {
  6260. // Objects that are members are not references
  6261. ctx->type.dataType.MakeReference(false);
  6262. }
  6263. // If the object reference is const, the property will also be const
  6264. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  6265. found = true;
  6266. }
  6267. else if( outFunc->objectType )
  6268. {
  6269. // If it is not a property, it may still be the name of a method which can be used to create delegates
  6270. asCObjectType *ot = outFunc->objectType;
  6271. asCScriptFunction *func = 0;
  6272. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6273. {
  6274. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  6275. {
  6276. func = engine->scriptFunctions[ot->methods[n]];
  6277. break;
  6278. }
  6279. }
  6280. if( func )
  6281. {
  6282. // An object method was found. Keep the name of the method in the expression, but
  6283. // don't actually modify the bytecode at this point since it is not yet known what
  6284. // the method will be used for, or even what overloaded method should be used.
  6285. ctx->methodName = name;
  6286. // Place the object pointer on the stack, as if the expression was this.func
  6287. if( !objType )
  6288. {
  6289. // The object pointer is located at stack position 0
  6290. // This is only done when accessing through the implicit this pointer
  6291. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6292. ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
  6293. ctx->type.dataType.MakeReference(true);
  6294. Dereference(ctx, true);
  6295. }
  6296. found = true;
  6297. }
  6298. }
  6299. }
  6300. }
  6301. // Recursively search parent namespaces for global entities
  6302. asCString currScope = scope;
  6303. if( scope == "" )
  6304. currScope = outFunc->nameSpace->name;
  6305. while( !found && !noGlobal && !objType )
  6306. {
  6307. asSNameSpace *ns = DetermineNameSpace(currScope);
  6308. // Is it a global property?
  6309. if( !found && ns )
  6310. {
  6311. // See if there are any matching global property accessors
  6312. asSExprContext access(engine);
  6313. int r = 0;
  6314. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6315. {
  6316. // This is an index access, check if there is a property accessor that takes an index arg
  6317. asSExprContext dummyArg(engine);
  6318. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  6319. }
  6320. if( r == 0 )
  6321. {
  6322. // Normal property access
  6323. r = FindPropertyAccessor(name, &access, errNode, ns);
  6324. }
  6325. if( r < 0 ) return -1;
  6326. if( access.property_get || access.property_set )
  6327. {
  6328. // Prepare the bytecode for the function call
  6329. MergeExprBytecodeAndType(ctx, &access);
  6330. found = true;
  6331. }
  6332. // See if there is any matching global property
  6333. if( !found )
  6334. {
  6335. bool isCompiled = true;
  6336. bool isPureConstant = false;
  6337. bool isAppProp = false;
  6338. asQWORD constantValue = 0;
  6339. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  6340. if( prop )
  6341. {
  6342. found = true;
  6343. // Verify that the global property has been compiled already
  6344. if( isCompiled )
  6345. {
  6346. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6347. {
  6348. ctx->type.dataType.MakeHandle(true);
  6349. ctx->type.isExplicitHandle = true;
  6350. }
  6351. // If the global property is a pure constant
  6352. // we can allow the compiler to optimize it. Pure
  6353. // constants are global constant variables that were
  6354. // initialized by literal constants.
  6355. if( isPureConstant )
  6356. ctx->type.SetConstantQW(prop->type, constantValue);
  6357. else
  6358. {
  6359. // A shared type must not access global vars, unless they
  6360. // too are shared, e.g. application registered vars
  6361. if( outFunc->IsShared() )
  6362. {
  6363. if( !isAppProp )
  6364. {
  6365. asCString str;
  6366. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  6367. Error(str, errNode);
  6368. // Allow the compilation to continue to catch other problems
  6369. }
  6370. }
  6371. ctx->type.Set(prop->type);
  6372. ctx->type.isLValue = true;
  6373. if( ctx->type.dataType.IsPrimitive() )
  6374. {
  6375. // Load the address of the variable into the register
  6376. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  6377. ctx->type.dataType.MakeReference(true);
  6378. }
  6379. else
  6380. {
  6381. // Push the address of the variable on the stack
  6382. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  6383. // If the object is a value type or a non-handle variable to a reference type,
  6384. // then we must validate the existance as it could potentially be accessed
  6385. // before it is initialized.
  6386. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6387. !ctx->type.dataType.IsObjectHandle() )
  6388. {
  6389. // TODO: runtime optimize: This is not necessary for application registered properties
  6390. ctx->bc.Instr(asBC_ChkRefS);
  6391. }
  6392. // If the address pushed on the stack is to a value type or an object
  6393. // handle, then mark the expression as a reference. Addresses to a reference
  6394. // type aren't marked as references to get correct behaviour
  6395. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6396. ctx->type.dataType.IsObjectHandle() )
  6397. {
  6398. ctx->type.dataType.MakeReference(true);
  6399. }
  6400. else
  6401. {
  6402. asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  6403. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  6404. ctx->bc.Instr(asBC_RDSPtr);
  6405. }
  6406. }
  6407. }
  6408. }
  6409. else
  6410. {
  6411. asCString str;
  6412. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  6413. Error(str, errNode);
  6414. return -1;
  6415. }
  6416. }
  6417. }
  6418. }
  6419. // Is it the name of a global function?
  6420. if( !noFunction && !found && ns )
  6421. {
  6422. asCArray<int> funcs;
  6423. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  6424. if( funcs.GetLength() > 0 )
  6425. {
  6426. found = true;
  6427. // Defer the evaluation of which function until it is actually used
  6428. // Store the namespace and name of the function for later
  6429. ctx->type.SetUndefinedFuncHandle(engine);
  6430. ctx->methodName = ns ? ns->name + "::" + name : name;
  6431. }
  6432. }
  6433. // Is it an enum value?
  6434. if( !found )
  6435. {
  6436. // The enum type may be declared in a namespace too
  6437. asCObjectType *scopeType = 0;
  6438. if( currScope != "" && currScope != "::" )
  6439. {
  6440. // Use the last scope name as the enum type
  6441. asCString enumType = currScope;
  6442. asCString nsScope;
  6443. int p = currScope.FindLast("::");
  6444. if( p != -1 )
  6445. {
  6446. enumType = currScope.SubString(p+2);
  6447. nsScope = currScope.SubString(0, p);
  6448. }
  6449. asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
  6450. if( ns )
  6451. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  6452. }
  6453. asDWORD value = 0;
  6454. asCDataType dt;
  6455. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  6456. {
  6457. // scoped enum value found
  6458. found = true;
  6459. }
  6460. else if( !engine->ep.requireEnumScope )
  6461. {
  6462. // Look for the enum value without explicitly informing the enum type
  6463. asSNameSpace *ns = DetermineNameSpace(currScope);
  6464. int e = 0;
  6465. if( ns )
  6466. e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  6467. if( e )
  6468. {
  6469. found = true;
  6470. if( e == 2 )
  6471. {
  6472. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  6473. }
  6474. }
  6475. }
  6476. if( found )
  6477. {
  6478. // Even if the enum type is not shared, and we're compiling a shared object,
  6479. // the use of the values are still allowed, since they are treated as constants.
  6480. // an enum value was resolved
  6481. ctx->type.SetConstantDW(dt, value);
  6482. }
  6483. else
  6484. {
  6485. // If nothing was found because the scope doesn't match a namespace or an enum
  6486. // then this should be reported as an error and the search interrupted
  6487. if( !ns && !scopeType )
  6488. {
  6489. ctx->type.SetDummy();
  6490. asCString str;
  6491. str.Format(TXT_UNKNOWN_SCOPE_s, currScope.AddressOf());
  6492. Error(str, errNode);
  6493. return -1;
  6494. }
  6495. }
  6496. }
  6497. if( !found )
  6498. {
  6499. if( currScope == "" || currScope == "::" )
  6500. break;
  6501. // Move up to parent namespace
  6502. int pos = currScope.FindLast("::");
  6503. if( pos >= 0 )
  6504. currScope = currScope.SubString(0, pos);
  6505. else
  6506. currScope = "::";
  6507. }
  6508. }
  6509. // The name doesn't match any variable
  6510. if( !found )
  6511. {
  6512. // Give dummy value
  6513. ctx->type.SetDummy();
  6514. if( !isOptional )
  6515. {
  6516. // Prepend the scope to the name for the error message
  6517. asCString ename;
  6518. if( scope != "" && scope != "::" )
  6519. ename = scope + "::";
  6520. else
  6521. ename = scope;
  6522. ename += name;
  6523. asCString str;
  6524. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  6525. Error(str, errNode);
  6526. // Declare the variable now so that it will not be reported again
  6527. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  6528. // Mark the variable as initialized so that the user will not be bother by it again
  6529. sVariable *v = variables->GetVariable(name.AddressOf());
  6530. asASSERT(v);
  6531. if( v ) v->isInitialized = true;
  6532. }
  6533. // Return -1 to signal that the variable wasn't found
  6534. return -1;
  6535. }
  6536. return 0;
  6537. }
  6538. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  6539. {
  6540. // Shouldn't receive any byte code
  6541. asASSERT(ctx->bc.GetLastInstr() == -1);
  6542. asCScriptNode *vnode = node->firstChild;
  6543. ctx->exprNode = vnode;
  6544. if( vnode->nodeType == snVariableAccess )
  6545. {
  6546. // Determine the scope resolution of the variable
  6547. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  6548. // Determine the name of the variable
  6549. asASSERT(vnode->nodeType == snIdentifier );
  6550. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  6551. return CompileVariableAccess(name, scope, ctx, node);
  6552. }
  6553. else if( vnode->nodeType == snConstant )
  6554. {
  6555. if( vnode->tokenType == ttIntConstant )
  6556. {
  6557. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6558. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  6559. // Do we need 64 bits?
  6560. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  6561. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  6562. if( val>>31 )
  6563. {
  6564. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  6565. if( val>>63 )
  6566. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6567. else
  6568. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  6569. }
  6570. else
  6571. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  6572. }
  6573. else if( vnode->tokenType == ttBitsConstant )
  6574. {
  6575. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6576. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  6577. // TODO: Check for overflow
  6578. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
  6579. // Do we need 64 bits?
  6580. if( val>>32 )
  6581. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6582. else
  6583. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  6584. }
  6585. else if( vnode->tokenType == ttFloatConstant )
  6586. {
  6587. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6588. // TODO: Check for overflow
  6589. size_t numScanned;
  6590. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  6591. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  6592. #ifndef AS_USE_DOUBLE_AS_FLOAT
  6593. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  6594. asASSERT(numScanned == vnode->tokenLength - 1);
  6595. #endif
  6596. }
  6597. else if( vnode->tokenType == ttDoubleConstant )
  6598. {
  6599. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6600. // TODO: Check for overflow
  6601. size_t numScanned;
  6602. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  6603. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  6604. asASSERT(numScanned == vnode->tokenLength);
  6605. }
  6606. else if( vnode->tokenType == ttTrue ||
  6607. vnode->tokenType == ttFalse )
  6608. {
  6609. #if AS_SIZEOF_BOOL == 1
  6610. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6611. #else
  6612. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6613. #endif
  6614. }
  6615. else if( vnode->tokenType == ttStringConstant ||
  6616. vnode->tokenType == ttMultilineStringConstant ||
  6617. vnode->tokenType == ttHeredocStringConstant )
  6618. {
  6619. asCString str;
  6620. asCScriptNode *snode = vnode->firstChild;
  6621. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  6622. {
  6623. // Treat the single quoted string as a single character literal
  6624. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6625. asDWORD val = 0;
  6626. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  6627. {
  6628. // This is the start of a UTF8 encoded character. We need to decode it
  6629. val = asStringDecodeUTF8(str.AddressOf(), 0);
  6630. if( val == (asDWORD)-1 )
  6631. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6632. }
  6633. else
  6634. {
  6635. val = ProcessStringConstant(str, snode);
  6636. if( val == (asDWORD)-1 )
  6637. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6638. }
  6639. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  6640. }
  6641. else
  6642. {
  6643. // Process the string constants
  6644. while( snode )
  6645. {
  6646. asCString cat;
  6647. if( snode->tokenType == ttStringConstant )
  6648. {
  6649. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6650. ProcessStringConstant(cat, snode);
  6651. }
  6652. else if( snode->tokenType == ttMultilineStringConstant )
  6653. {
  6654. if( !engine->ep.allowMultilineStrings )
  6655. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  6656. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6657. ProcessStringConstant(cat, snode);
  6658. }
  6659. else if( snode->tokenType == ttHeredocStringConstant )
  6660. {
  6661. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  6662. ProcessHeredocStringConstant(cat, snode);
  6663. }
  6664. str += cat;
  6665. snode = snode->next;
  6666. }
  6667. // Call the string factory function to create a string object
  6668. asCScriptFunction *descr = engine->stringFactory;
  6669. if( descr == 0 )
  6670. {
  6671. // Error
  6672. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  6673. // Give dummy value
  6674. ctx->type.SetDummy();
  6675. return -1;
  6676. }
  6677. else
  6678. {
  6679. // Register the constant string with the engine
  6680. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  6681. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  6682. bool useVariable = false;
  6683. int stackOffset = 0;
  6684. if( descr->DoesReturnOnStack() )
  6685. {
  6686. useVariable = true;
  6687. stackOffset = AllocateVariable(descr->returnType, true);
  6688. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  6689. }
  6690. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  6691. }
  6692. }
  6693. }
  6694. else if( vnode->tokenType == ttNull )
  6695. {
  6696. ctx->bc.Instr(asBC_PshNull);
  6697. ctx->type.SetNullConstant();
  6698. }
  6699. else
  6700. asASSERT(false);
  6701. }
  6702. else if( vnode->nodeType == snFunctionCall )
  6703. {
  6704. // Determine the scope resolution
  6705. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  6706. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  6707. }
  6708. else if( vnode->nodeType == snConstructCall )
  6709. {
  6710. CompileConstructCall(vnode, ctx);
  6711. }
  6712. else if( vnode->nodeType == snAssignment )
  6713. {
  6714. asSExprContext e(engine);
  6715. int r = CompileAssignment(vnode, &e);
  6716. if( r < 0 )
  6717. {
  6718. ctx->type.SetDummy();
  6719. return r;
  6720. }
  6721. MergeExprBytecodeAndType(ctx, &e);
  6722. }
  6723. else if( vnode->nodeType == snCast )
  6724. {
  6725. // Implement the cast operator
  6726. CompileConversion(vnode, ctx);
  6727. }
  6728. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  6729. {
  6730. // This is a void expression
  6731. ctx->type.SetVoidExpression();
  6732. }
  6733. else
  6734. asASSERT(false);
  6735. return 0;
  6736. }
  6737. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  6738. {
  6739. int charLiteral = -1;
  6740. // Process escape sequences
  6741. asCArray<char> str((int)cstr.GetLength());
  6742. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  6743. {
  6744. #ifdef AS_DOUBLEBYTE_CHARSET
  6745. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  6746. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  6747. {
  6748. // This is the lead character of a double byte character
  6749. // include the trail character without checking it's value.
  6750. str.PushLast(cstr[n]);
  6751. n++;
  6752. str.PushLast(cstr[n]);
  6753. continue;
  6754. }
  6755. #endif
  6756. asUINT val;
  6757. if( processEscapeSequences && cstr[n] == '\\' )
  6758. {
  6759. ++n;
  6760. if( n == cstr.GetLength() )
  6761. {
  6762. if( charLiteral == -1 ) charLiteral = 0;
  6763. return charLiteral;
  6764. }
  6765. // Hexadecimal escape sequences will allow the construction of
  6766. // invalid unicode sequences, but the string should also work as
  6767. // a bytearray so we must support this. The code for working with
  6768. // unicode text must be prepared to handle invalid unicode sequences
  6769. if( cstr[n] == 'x' || cstr[n] == 'X' )
  6770. {
  6771. ++n;
  6772. if( n == cstr.GetLength() ) break;
  6773. val = 0;
  6774. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  6775. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  6776. {
  6777. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6778. val = val*16 + cstr[n] - '0';
  6779. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6780. val = val*16 + cstr[n] - 'a' + 10;
  6781. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6782. val = val*16 + cstr[n] - 'A' + 10;
  6783. else
  6784. break;
  6785. }
  6786. // Rewind one, since the loop will increment it again
  6787. n--;
  6788. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  6789. if( engine->ep.stringEncoding == 0 )
  6790. {
  6791. str.PushLast((asBYTE)val);
  6792. }
  6793. else
  6794. {
  6795. #ifndef AS_BIG_ENDIAN
  6796. str.PushLast((asBYTE)val);
  6797. str.PushLast((asBYTE)(val>>8));
  6798. #else
  6799. str.PushLast((asBYTE)(val>>8));
  6800. str.PushLast((asBYTE)val);
  6801. #endif
  6802. }
  6803. if( charLiteral == -1 ) charLiteral = val;
  6804. continue;
  6805. }
  6806. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  6807. {
  6808. // \u expects 4 hex digits
  6809. // \U expects 8 hex digits
  6810. bool expect2 = cstr[n] == 'u';
  6811. int c = expect2 ? 4 : 8;
  6812. val = 0;
  6813. for( ; c > 0; c-- )
  6814. {
  6815. ++n;
  6816. if( n == cstr.GetLength() ) break;
  6817. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6818. val = val*16 + cstr[n] - '0';
  6819. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6820. val = val*16 + cstr[n] - 'a' + 10;
  6821. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6822. val = val*16 + cstr[n] - 'A' + 10;
  6823. else
  6824. break;
  6825. }
  6826. if( c != 0 )
  6827. {
  6828. // Give warning about invalid code point
  6829. // TODO: Need code position for warning
  6830. asCString msg;
  6831. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  6832. Warning(msg, node);
  6833. continue;
  6834. }
  6835. }
  6836. else
  6837. {
  6838. if( cstr[n] == '"' )
  6839. val = '"';
  6840. else if( cstr[n] == '\'' )
  6841. val = '\'';
  6842. else if( cstr[n] == 'n' )
  6843. val = '\n';
  6844. else if( cstr[n] == 'r' )
  6845. val = '\r';
  6846. else if( cstr[n] == 't' )
  6847. val = '\t';
  6848. else if( cstr[n] == '0' )
  6849. val = '\0';
  6850. else if( cstr[n] == '\\' )
  6851. val = '\\';
  6852. else
  6853. {
  6854. // Invalid escape sequence
  6855. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  6856. continue;
  6857. }
  6858. }
  6859. }
  6860. else
  6861. {
  6862. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  6863. {
  6864. unsigned int len;
  6865. val = asStringDecodeUTF8(&cstr[n], &len);
  6866. if( val == 0xFFFFFFFF )
  6867. {
  6868. // Incorrect UTF8 encoding. Use only the first byte
  6869. // TODO: Need code position for warning
  6870. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  6871. val = (unsigned char)cstr[n];
  6872. }
  6873. else
  6874. n += len-1;
  6875. }
  6876. else
  6877. val = (unsigned char)cstr[n];
  6878. }
  6879. // Add the character to the final string
  6880. char encodedValue[5];
  6881. int len;
  6882. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  6883. {
  6884. // Convert to UTF8 encoded
  6885. len = asStringEncodeUTF8(val, encodedValue);
  6886. }
  6887. else if( engine->ep.stringEncoding == 1 )
  6888. {
  6889. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  6890. len = asStringEncodeUTF16(val, encodedValue);
  6891. }
  6892. else
  6893. {
  6894. // Do not convert ASCII characters
  6895. encodedValue[0] = (asBYTE)val;
  6896. len = 1;
  6897. }
  6898. if( len < 0 )
  6899. {
  6900. // Give warning about invalid code point
  6901. // TODO: Need code position for warning
  6902. Warning(TXT_INVALID_UNICODE_VALUE, node);
  6903. }
  6904. else
  6905. {
  6906. // Add the encoded value to the final string
  6907. str.Concatenate(encodedValue, len);
  6908. if( charLiteral == -1 ) charLiteral = val;
  6909. }
  6910. }
  6911. cstr.Assign(str.AddressOf(), str.GetLength());
  6912. return charLiteral;
  6913. }
  6914. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  6915. {
  6916. // Remove first line if it only contains whitespace
  6917. int start;
  6918. for( start = 0; start < (int)str.GetLength(); start++ )
  6919. {
  6920. if( str[start] == '\n' )
  6921. {
  6922. // Remove the linebreak as well
  6923. start++;
  6924. break;
  6925. }
  6926. if( str[start] != ' ' &&
  6927. str[start] != '\t' &&
  6928. str[start] != '\r' )
  6929. {
  6930. // Don't remove anything
  6931. start = 0;
  6932. break;
  6933. }
  6934. }
  6935. // Remove the line after the last line break if it only contains whitespaces
  6936. int end;
  6937. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  6938. {
  6939. if( str[end] == '\n' )
  6940. {
  6941. // Don't remove the last line break
  6942. end++;
  6943. break;
  6944. }
  6945. if( str[end] != ' ' &&
  6946. str[end] != '\t' &&
  6947. str[end] != '\r' )
  6948. {
  6949. // Don't remove anything
  6950. end = (int)str.GetLength();
  6951. break;
  6952. }
  6953. }
  6954. if( end < 0 ) end = 0;
  6955. asCString tmp;
  6956. if( end > start )
  6957. tmp.Assign(&str[start], end-start);
  6958. ProcessStringConstant(tmp, node, false);
  6959. str = tmp;
  6960. }
  6961. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  6962. {
  6963. asSExprContext expr(engine);
  6964. asCDataType to;
  6965. bool anyErrors = false;
  6966. EImplicitConv convType;
  6967. if( node->nodeType == snConstructCall )
  6968. {
  6969. convType = asIC_EXPLICIT_VAL_CAST;
  6970. // Verify that there is only one argument
  6971. if( node->lastChild->firstChild == 0 ||
  6972. node->lastChild->firstChild != node->lastChild->lastChild )
  6973. {
  6974. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  6975. expr.type.SetDummy();
  6976. anyErrors = true;
  6977. }
  6978. else
  6979. {
  6980. // Compile the expression
  6981. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  6982. if( r < 0 )
  6983. anyErrors = true;
  6984. }
  6985. // Determine the requested type
  6986. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6987. to.MakeReadOnly(true); // Default to const
  6988. asASSERT(to.IsPrimitive());
  6989. }
  6990. else
  6991. {
  6992. convType = asIC_EXPLICIT_REF_CAST;
  6993. // Compile the expression
  6994. int r = CompileAssignment(node->lastChild, &expr);
  6995. if( r < 0 )
  6996. anyErrors = true;
  6997. // Determine the requested type
  6998. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6999. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  7000. // If the type support object handles, then use it
  7001. if( to.SupportHandles() )
  7002. {
  7003. to.MakeHandle(true);
  7004. }
  7005. else if( !to.IsObjectHandle() )
  7006. {
  7007. // The cast<type> operator can only be used for reference casts
  7008. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  7009. anyErrors = true;
  7010. }
  7011. }
  7012. // Do not allow casting to non shared type if we're compiling a shared method
  7013. if( outFunc->IsShared() &&
  7014. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  7015. {
  7016. asCString msg;
  7017. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  7018. Error(msg, node);
  7019. anyErrors = true;
  7020. }
  7021. if( anyErrors )
  7022. {
  7023. // Assume that the error can be fixed and allow the compilation to continue
  7024. ctx->type.SetConstantDW(to, 0);
  7025. return;
  7026. }
  7027. ProcessPropertyGetAccessor(&expr, node);
  7028. // Don't allow any operators on expressions that take address of class method
  7029. if( expr.IsClassMethod() )
  7030. {
  7031. Error(TXT_INVALID_OP_ON_METHOD, node);
  7032. return;
  7033. }
  7034. // We don't want a reference for conversion casts
  7035. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  7036. {
  7037. if( expr.type.dataType.IsObject() )
  7038. Dereference(&expr, true);
  7039. else
  7040. ConvertToVariable(&expr);
  7041. }
  7042. ImplicitConversion(&expr, to, node, convType);
  7043. IsVariableInitialized(&expr.type, node);
  7044. // If no type conversion is really tried ignore it
  7045. if( to == expr.type.dataType )
  7046. {
  7047. // This will keep information about constant type
  7048. MergeExprBytecode(ctx, &expr);
  7049. ctx->type = expr.type;
  7050. return;
  7051. }
  7052. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  7053. {
  7054. MergeExprBytecode(ctx, &expr);
  7055. ctx->type = expr.type;
  7056. ctx->type.dataType.MakeReadOnly(true);
  7057. return;
  7058. }
  7059. // The implicit conversion already does most of the conversions permitted,
  7060. // here we'll only treat those conversions that require an explicit cast.
  7061. bool conversionOK = false;
  7062. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  7063. {
  7064. if( !expr.type.dataType.IsObject() )
  7065. ConvertToTempVariable(&expr);
  7066. if( to.IsObjectHandle() &&
  7067. expr.type.dataType.IsObjectHandle() &&
  7068. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  7069. {
  7070. conversionOK = CompileRefCast(&expr, to, true, node);
  7071. MergeExprBytecode(ctx, &expr);
  7072. ctx->type = expr.type;
  7073. }
  7074. }
  7075. if( conversionOK )
  7076. return;
  7077. // Conversion not available
  7078. ctx->type.SetDummy();
  7079. asCString strTo, strFrom;
  7080. strTo = to.Format();
  7081. strFrom = expr.type.dataType.Format();
  7082. asCString msg;
  7083. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  7084. Error(msg, node);
  7085. }
  7086. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  7087. {
  7088. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  7089. // Parameters that are sent by reference should be assigned
  7090. // to the evaluated expression if it is an lvalue
  7091. // Evaluate the arguments from last to first
  7092. int n = (int)descr->parameterTypes.GetLength() - 1;
  7093. for( ; n >= 0; n-- )
  7094. {
  7095. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  7096. (descr->parameterTypes[n].IsObject() && deferAll) )
  7097. {
  7098. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  7099. // For &inout, only store the argument if it is for a temporary variable
  7100. if( engine->ep.allowUnsafeReferences ||
  7101. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  7102. {
  7103. // Store the argument for later processing
  7104. asSDeferredParam outParam;
  7105. outParam.argNode = args[n]->exprNode;
  7106. outParam.argType = args[n]->type;
  7107. outParam.argInOutFlags = descr->inOutFlags[n];
  7108. outParam.origExpr = args[n]->origExpr;
  7109. ctx->deferredParams.PushLast(outParam);
  7110. }
  7111. }
  7112. else
  7113. {
  7114. // Release the temporary variable now
  7115. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  7116. }
  7117. // Move the argument's deferred expressions over to the final expression
  7118. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  7119. {
  7120. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  7121. args[n]->deferredParams[m].origExpr = 0;
  7122. }
  7123. args[n]->deferredParams.SetLength(0);
  7124. }
  7125. }
  7126. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  7127. {
  7128. if( isProcessingDeferredParams ) return;
  7129. isProcessingDeferredParams = true;
  7130. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  7131. {
  7132. asSDeferredParam outParam = ctx->deferredParams[n];
  7133. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  7134. {
  7135. // Just release the variable
  7136. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7137. }
  7138. else if( outParam.argInOutFlags == asTM_OUTREF )
  7139. {
  7140. asSExprContext *expr = outParam.origExpr;
  7141. outParam.origExpr = 0;
  7142. if( outParam.argType.dataType.IsObjectHandle() )
  7143. {
  7144. // Implicitly convert the value to a handle
  7145. if( expr->type.dataType.IsObjectHandle() )
  7146. expr->type.isExplicitHandle = true;
  7147. }
  7148. // Verify that the expression result in a lvalue, or a property accessor
  7149. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  7150. {
  7151. asSExprContext rctx(engine);
  7152. rctx.type = outParam.argType;
  7153. if( rctx.type.dataType.IsPrimitive() )
  7154. rctx.type.dataType.MakeReference(false);
  7155. else
  7156. {
  7157. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  7158. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  7159. if( expr->type.isExplicitHandle )
  7160. rctx.type.isExplicitHandle = true;
  7161. }
  7162. asSExprContext o(engine);
  7163. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  7164. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  7165. // The assignment may itself have resulted in a new temporary variable, e.g. if
  7166. // the opAssign returns a non-reference. We must release this temporary variable
  7167. // since it won't be used
  7168. ReleaseTemporaryVariable(o.type, &o.bc);
  7169. MergeExprBytecode(ctx, &o);
  7170. }
  7171. else
  7172. {
  7173. // We must still evaluate the expression
  7174. MergeExprBytecode(ctx, expr);
  7175. if( !expr->type.IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  7176. ctx->bc.Instr(asBC_PopPtr);
  7177. // Give a warning, except if the argument is void, null or 0 which indicate the argument is really to be ignored
  7178. if( !expr->type.IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  7179. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  7180. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7181. }
  7182. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  7183. // Delete the original expression context
  7184. asDELETE(expr,asSExprContext);
  7185. }
  7186. else // &inout
  7187. {
  7188. if( outParam.argType.isTemporary )
  7189. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7190. else if( !outParam.argType.isVariable )
  7191. {
  7192. if( outParam.argType.dataType.IsObject() &&
  7193. ((outParam.argType.dataType.GetBehaviour()->addref &&
  7194. outParam.argType.dataType.GetBehaviour()->release) ||
  7195. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  7196. {
  7197. // Release the object handle that was taken to guarantee the reference
  7198. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7199. }
  7200. }
  7201. }
  7202. }
  7203. ctx->deferredParams.SetLength(0);
  7204. isProcessingDeferredParams = false;
  7205. }
  7206. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  7207. {
  7208. // The first node is a datatype node
  7209. asCString name;
  7210. asCTypeInfo tempObj;
  7211. bool onHeap = true;
  7212. asCArray<int> funcs;
  7213. // It is possible that the name is really a constructor
  7214. asCDataType dt;
  7215. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7216. if( dt.IsPrimitive() )
  7217. {
  7218. // This is a cast to a primitive type
  7219. CompileConversion(node, ctx);
  7220. return;
  7221. }
  7222. // Do not allow constructing non-shared types in shared functions
  7223. if( outFunc->IsShared() &&
  7224. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  7225. {
  7226. asCString msg;
  7227. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  7228. Error(msg, node);
  7229. }
  7230. // Compile the arguments
  7231. asCArray<asSExprContext *> args;
  7232. asCArray<asCTypeInfo> temporaryVariables;
  7233. if( CompileArgumentList(node->lastChild, args) >= 0 )
  7234. {
  7235. // Check for a value cast behaviour
  7236. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  7237. {
  7238. asSExprContext conv(engine);
  7239. conv.type = args[0]->type;
  7240. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  7241. if( conv.type.dataType.IsEqualExceptRef(dt) )
  7242. {
  7243. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  7244. ctx->bc.AddCode(&args[0]->bc);
  7245. ctx->type = args[0]->type;
  7246. asDELETE(args[0],asSExprContext);
  7247. return;
  7248. }
  7249. }
  7250. // Check for possible constructor/factory
  7251. name = dt.Format();
  7252. asSTypeBehaviour *beh = dt.GetBehaviour();
  7253. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7254. {
  7255. funcs = beh->constructors;
  7256. // Value types and script types are allocated through the constructor
  7257. tempObj.dataType = dt;
  7258. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  7259. tempObj.dataType.MakeReference(true);
  7260. tempObj.isTemporary = true;
  7261. tempObj.isVariable = true;
  7262. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  7263. // Push the address of the object on the stack
  7264. if( onHeap )
  7265. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  7266. }
  7267. else
  7268. {
  7269. funcs = beh->factories;
  7270. }
  7271. // Special case: Allow calling func(void) with a void expression.
  7272. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  7273. {
  7274. // Evaluate the expression before the function call
  7275. MergeExprBytecode(ctx, args[0]);
  7276. asDELETE(args[0],asSExprContext);
  7277. args.SetLength(0);
  7278. }
  7279. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  7280. // If none has been registered, just allocate the variable and push it on the stack.
  7281. if( args.GetLength() == 0 )
  7282. {
  7283. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  7284. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  7285. {
  7286. // Call the default constructor
  7287. ctx->type = tempObj;
  7288. if( onHeap )
  7289. {
  7290. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  7291. ctx->bc.RemoveLastInstr();
  7292. }
  7293. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  7294. // Push the reference on the stack
  7295. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7296. return;
  7297. }
  7298. }
  7299. // Special case: If this is a construction of a delegate and the expression names an object method
  7300. if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
  7301. {
  7302. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  7303. // case no object delegate will be created, but instead a delegate for a function pointer
  7304. // In theory a simple cast would be good in this case, but this is a construct call so it
  7305. // is expected that a new object is created.
  7306. dt.MakeHandle(true);
  7307. ctx->type.Set(dt);
  7308. // The delegate must be able to hold on to a reference to the object
  7309. if( !args[0]->type.dataType.SupportHandles() )
  7310. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  7311. else
  7312. {
  7313. // Filter the available object methods to find the one that matches the func def
  7314. asCObjectType *type = args[0]->type.dataType.GetObjectType();
  7315. asCScriptFunction *bestMethod = 0;
  7316. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  7317. {
  7318. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  7319. if( func->name != args[0]->methodName )
  7320. continue;
  7321. // If the expression is for a const object, then only const methods should be accepted
  7322. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  7323. continue;
  7324. if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
  7325. {
  7326. bestMethod = func;
  7327. // If the expression is non-const the non-const overloaded method has priority
  7328. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  7329. break;
  7330. }
  7331. }
  7332. if( bestMethod )
  7333. {
  7334. // The object pointer is already on the stack
  7335. MergeExprBytecode(ctx, args[0]);
  7336. // Push the function pointer as an additional argument
  7337. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  7338. // Call the factory function for the delegate
  7339. asCArray<int> funcs;
  7340. builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
  7341. asASSERT( funcs.GetLength() == 1 );
  7342. ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
  7343. // Store the returned delegate in a temporary variable
  7344. int returnOffset = AllocateVariable(dt, true, false);
  7345. dt.MakeReference(true);
  7346. ctx->type.SetVariable(dt, returnOffset, true);
  7347. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  7348. // Push a reference to the temporary variable on the stack
  7349. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  7350. }
  7351. else
  7352. {
  7353. asCString msg;
  7354. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
  7355. Error(msg.AddressOf(), node);
  7356. }
  7357. }
  7358. // Clean-up arg
  7359. asDELETE(args[0],asSExprContext);
  7360. return;
  7361. }
  7362. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  7363. if( funcs.GetLength() != 1 )
  7364. {
  7365. // The error was reported by MatchFunctions()
  7366. // Dummy value
  7367. ctx->type.SetDummy();
  7368. }
  7369. else
  7370. {
  7371. int r = asSUCCESS;
  7372. // Add the default values for arguments not explicitly supplied
  7373. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  7374. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7375. r = CompileDefaultArgs(node, args, func);
  7376. if( r == asSUCCESS )
  7377. {
  7378. asCByteCode objBC(engine);
  7379. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  7380. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  7381. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7382. {
  7383. // If the object is allocated on the stack, then call the constructor as a normal function
  7384. if( onHeap )
  7385. {
  7386. int offset = 0;
  7387. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  7388. for( asUINT n = 0; n < args.GetLength(); n++ )
  7389. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  7390. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  7391. }
  7392. else
  7393. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7394. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  7395. // Add tag that the object has been initialized
  7396. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  7397. // The constructor doesn't return anything,
  7398. // so we have to manually inform the type of
  7399. // the return value
  7400. ctx->type = tempObj;
  7401. if( !onHeap )
  7402. ctx->type.dataType.MakeReference(false);
  7403. // Push the address of the object on the stack again
  7404. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7405. }
  7406. else
  7407. {
  7408. // Call the factory to create the reference type
  7409. PerformFunctionCall(funcs[0], ctx, false, &args);
  7410. }
  7411. }
  7412. }
  7413. }
  7414. else
  7415. {
  7416. // Failed to compile the argument list, set the result to the dummy type
  7417. ctx->type.SetDummy();
  7418. }
  7419. // Cleanup
  7420. for( asUINT n = 0; n < args.GetLength(); n++ )
  7421. if( args[n] )
  7422. {
  7423. asDELETE(args[n],asSExprContext);
  7424. }
  7425. }
  7426. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  7427. {
  7428. asCString name;
  7429. asCTypeInfo tempObj;
  7430. asCArray<int> funcs;
  7431. int localVar = -1;
  7432. bool initializeMembers = false;
  7433. asCScriptNode *nm = node->lastChild->prev;
  7434. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  7435. // First check for a local variable of a function type as it would take precedence
  7436. // Must not allow function names, nor global variables to be returned in this instance
  7437. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  7438. asSExprContext funcPtr(engine);
  7439. if( objectType == 0 )
  7440. {
  7441. localVar = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true);
  7442. if( localVar >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7443. {
  7444. // The variable is not a function
  7445. asCString msg;
  7446. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7447. Error(msg, node);
  7448. return -1;
  7449. }
  7450. // If the name matches a method name, then reset the indicator that nothing was found
  7451. if( funcPtr.methodName != "" )
  7452. localVar = -1;
  7453. }
  7454. if( localVar < 0 )
  7455. {
  7456. // If this is an expression post op, or if a class method is
  7457. // being compiled, then we should look for matching class methods
  7458. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  7459. {
  7460. // If we're compiling a constructor and the name of the function is super then
  7461. // the constructor of the base class is being called.
  7462. // super cannot be prefixed with a scope operator
  7463. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  7464. {
  7465. // If the class is not derived from anyone else, calling super should give an error
  7466. if( outFunc && outFunc->objectType->derivedFrom )
  7467. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  7468. // Must not allow calling base class' constructor multiple times
  7469. if( continueLabels.GetLength() > 0 )
  7470. {
  7471. // If a continue label is set we are in a loop
  7472. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  7473. }
  7474. else if( breakLabels.GetLength() > 0 )
  7475. {
  7476. // TODO: inheritance: Should eventually allow constructors in switch statements
  7477. // If a break label is set we are either in a loop or a switch statements
  7478. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  7479. }
  7480. else if( m_isConstructorCalled )
  7481. {
  7482. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  7483. }
  7484. m_isConstructorCalled = true;
  7485. // We need to initialize the class members, but only after all the deferred arguments have been completed
  7486. initializeMembers = true;
  7487. }
  7488. else
  7489. {
  7490. // The scope is can be used to specify the base class
  7491. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope);
  7492. }
  7493. // It is still possible that there is a class member of a function type
  7494. if( funcs.GetLength() == 0 )
  7495. {
  7496. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true, objectType);
  7497. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7498. {
  7499. // The variable is not a function
  7500. asCString msg;
  7501. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7502. Error(msg, node);
  7503. return -1;
  7504. }
  7505. }
  7506. // If a class method is being called implicitly, then add the this pointer for the call
  7507. if( funcs.GetLength() && !objectType )
  7508. {
  7509. objectType = outFunc->objectType;
  7510. asCDataType dt = asCDataType::CreateObject(objectType, false);
  7511. // The object pointer is located at stack position 0
  7512. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7513. ctx->type.SetVariable(dt, 0, false);
  7514. ctx->type.dataType.MakeReference(true);
  7515. Dereference(ctx, true);
  7516. }
  7517. }
  7518. // If it is not a class method or member function pointer,
  7519. // then look for global functions or global function pointers,
  7520. // unless this is an expression post op, incase only member
  7521. // functions are expected
  7522. if( objectType == 0 && funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() == 0 )
  7523. {
  7524. // The scope is used to define the namespace
  7525. asSNameSpace *ns = DetermineNameSpace(scope);
  7526. if( ns )
  7527. {
  7528. // Search recursively in parent namespaces
  7529. while( ns && funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() == 0 )
  7530. {
  7531. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7532. if( funcs.GetLength() == 0 )
  7533. {
  7534. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  7535. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() )
  7536. {
  7537. // The variable is not a function
  7538. asCString msg;
  7539. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7540. Error(msg, node);
  7541. return -1;
  7542. }
  7543. }
  7544. ns = builder->GetParentNameSpace(ns);
  7545. }
  7546. }
  7547. else
  7548. {
  7549. asCString msg;
  7550. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  7551. Error(msg, node);
  7552. return -1;
  7553. }
  7554. }
  7555. }
  7556. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  7557. {
  7558. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  7559. }
  7560. // Compile the arguments
  7561. asCArray<asSExprContext *> args;
  7562. asCArray<asCTypeInfo> temporaryVariables;
  7563. if( CompileArgumentList(node->lastChild, args) >= 0 )
  7564. {
  7565. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  7566. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) && !args[0]->type.IsVoidExpression() )
  7567. {
  7568. // Evaluate the expression before the function call
  7569. MergeExprBytecode(ctx, args[0]);
  7570. asDELETE(args[0],asSExprContext);
  7571. args.SetLength(0);
  7572. }
  7573. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  7574. if( funcs.GetLength() != 1 )
  7575. {
  7576. // The error was reported by MatchFunctions()
  7577. // Dummy value
  7578. ctx->type.SetDummy();
  7579. }
  7580. else
  7581. {
  7582. int r = asSUCCESS;
  7583. // Add the default values for arguments not explicitly supplied
  7584. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  7585. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7586. r = CompileDefaultArgs(node, args, func);
  7587. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  7588. // is it enough to make sure it is in a local variable?
  7589. // For function pointer we must guarantee that the function is safe, i.e.
  7590. // by first storing the function pointer in a local variable (if it isn't already in one)
  7591. if( r == asSUCCESS )
  7592. {
  7593. if( func->funcType == asFUNC_FUNCDEF )
  7594. {
  7595. if( objectType && funcPtr.property_get <= 0 )
  7596. {
  7597. Dereference(ctx, true); // Dereference the object pointer to access the member
  7598. // The actual function should be called as if a global function
  7599. objectType = 0;
  7600. }
  7601. if( funcPtr.property_get > 0 )
  7602. {
  7603. ProcessPropertyGetAccessor(&funcPtr, node);
  7604. Dereference(&funcPtr, true);
  7605. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7606. funcPtr.bc.Instr(asBC_PopPtr);
  7607. }
  7608. else
  7609. {
  7610. Dereference(&funcPtr, true);
  7611. ConvertToVariable(&funcPtr);
  7612. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7613. if( !funcPtr.type.isTemporary )
  7614. funcPtr.bc.Instr(asBC_PopPtr);
  7615. }
  7616. MergeExprBytecodeAndType(ctx, &funcPtr);
  7617. }
  7618. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  7619. // If the function pointer was copied to a local variable for the call, then
  7620. // release it again (temporary local variable)
  7621. if( (funcs[0] & FUNC_IMPORTED) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  7622. {
  7623. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  7624. }
  7625. }
  7626. }
  7627. }
  7628. else
  7629. {
  7630. // Failed to compile the argument list, set the dummy type and continue compilation
  7631. ctx->type.SetDummy();
  7632. }
  7633. // Cleanup
  7634. for( asUINT n = 0; n < args.GetLength(); n++ )
  7635. if( args[n] )
  7636. {
  7637. asDELETE(args[n],asSExprContext);
  7638. }
  7639. if( initializeMembers )
  7640. {
  7641. asASSERT( m_isConstructor );
  7642. // Need to initialize members here, as they may use the properties of the base class
  7643. // If there are multiple paths that call super(), then there will also be multiple
  7644. // locations with initializations of the members. It is not possible to consolidate
  7645. // these in one place, as the expressions for the initialization are evaluated where
  7646. // they are compiled, which means that they may access different variables depending
  7647. // on the scope where super() is called.
  7648. // Members that don't have an explicit initialization expression will be initialized
  7649. // beginning of the constructor as they are guaranteed not to use at the any
  7650. // members of the base class.
  7651. CompileMemberInitialization(&ctx->bc, false);
  7652. }
  7653. return 0;
  7654. }
  7655. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  7656. {
  7657. asSNameSpace *ns;
  7658. if( scope == "" )
  7659. {
  7660. if( outFunc->nameSpace->name != "" )
  7661. ns = outFunc->nameSpace;
  7662. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  7663. ns = outFunc->objectType->nameSpace;
  7664. else
  7665. ns = engine->nameSpaces[0];
  7666. }
  7667. else if( scope == "::" )
  7668. ns = engine->nameSpaces[0];
  7669. else
  7670. ns = engine->FindNameSpace(scope.AddressOf());
  7671. return ns;
  7672. }
  7673. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  7674. {
  7675. int op = node->tokenType;
  7676. // Don't allow any prefix operators except handle on expressions that take address of class method
  7677. if( ctx->IsClassMethod() && op != ttHandle )
  7678. {
  7679. Error(TXT_INVALID_OP_ON_METHOD, node);
  7680. return -1;
  7681. }
  7682. // Don't allow any operators on void expressions
  7683. if( ctx->type.IsVoidExpression() )
  7684. {
  7685. Error(TXT_VOID_CANT_BE_OPERAND, node);
  7686. return -1;
  7687. }
  7688. IsVariableInitialized(&ctx->type, node);
  7689. if( op == ttHandle )
  7690. {
  7691. if( ctx->methodName != "" )
  7692. {
  7693. // Don't allow taking the handle of a handle
  7694. if( ctx->type.isExplicitHandle )
  7695. {
  7696. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7697. return -1;
  7698. }
  7699. }
  7700. else
  7701. {
  7702. // Don't allow taking handle of a handle, i.e. @@
  7703. if( ctx->type.isExplicitHandle )
  7704. {
  7705. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7706. return -1;
  7707. }
  7708. // @null is allowed even though it is implicit
  7709. if( !ctx->type.IsNullConstant() )
  7710. {
  7711. // Verify that the type allow its handle to be taken
  7712. if( !ctx->type.dataType.IsObject() ||
  7713. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  7714. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  7715. {
  7716. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7717. return -1;
  7718. }
  7719. // Objects that are not local variables are not references
  7720. // Objects allocated on the stack are also not marked as references
  7721. if( !ctx->type.dataType.IsReference() &&
  7722. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  7723. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  7724. {
  7725. Error(TXT_NOT_VALID_REFERENCE, node);
  7726. return -1;
  7727. }
  7728. // Convert the expression to a handle
  7729. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  7730. {
  7731. asCDataType to = ctx->type.dataType;
  7732. to.MakeHandle(true);
  7733. to.MakeReference(true);
  7734. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  7735. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  7736. asASSERT( ctx->type.dataType.IsObjectHandle() );
  7737. }
  7738. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  7739. {
  7740. // For the ASHANDLE type we'll simply set the expression as a handle
  7741. ctx->type.dataType.MakeHandle(true);
  7742. }
  7743. }
  7744. }
  7745. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  7746. ctx->type.isExplicitHandle = true;
  7747. }
  7748. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7749. {
  7750. // Look for the appropriate method
  7751. // There is no overloadable operator for unary plus
  7752. const char *opName = 0;
  7753. switch( op )
  7754. {
  7755. case ttMinus: opName = "opNeg"; break;
  7756. case ttBitNot: opName = "opCom"; break;
  7757. case ttInc: opName = "opPreInc"; break;
  7758. case ttDec: opName = "opPreDec"; break;
  7759. }
  7760. if( opName )
  7761. {
  7762. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7763. ProcessPropertyGetAccessor(ctx, node);
  7764. // Is it a const value?
  7765. bool isConst = false;
  7766. if( ctx->type.dataType.IsObjectHandle() )
  7767. isConst = ctx->type.dataType.IsHandleToConst();
  7768. else
  7769. isConst = ctx->type.dataType.IsReadOnly();
  7770. // 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
  7771. // Find the correct method
  7772. asCArray<int> funcs;
  7773. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7774. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7775. {
  7776. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7777. if( func->name == opName &&
  7778. func->parameterTypes.GetLength() == 0 &&
  7779. (!isConst || func->isReadOnly) )
  7780. {
  7781. funcs.PushLast(func->id);
  7782. }
  7783. }
  7784. // Did we find the method?
  7785. if( funcs.GetLength() == 1 )
  7786. {
  7787. asCTypeInfo objType = ctx->type;
  7788. asCArray<asSExprContext *> args;
  7789. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7790. ReleaseTemporaryVariable(objType, &ctx->bc);
  7791. return 0;
  7792. }
  7793. else if( funcs.GetLength() == 0 )
  7794. {
  7795. asCString str;
  7796. str = asCString(opName) + "()";
  7797. if( isConst )
  7798. str += " const";
  7799. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7800. Error(str, node);
  7801. ctx->type.SetDummy();
  7802. return -1;
  7803. }
  7804. else if( funcs.GetLength() > 1 )
  7805. {
  7806. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7807. PrintMatchingFuncs(funcs, node);
  7808. ctx->type.SetDummy();
  7809. return -1;
  7810. }
  7811. }
  7812. else if( op == ttPlus )
  7813. {
  7814. Error(TXT_ILLEGAL_OPERATION, node);
  7815. ctx->type.SetDummy();
  7816. return -1;
  7817. }
  7818. }
  7819. else if( op == ttPlus || op == ttMinus )
  7820. {
  7821. // This is only for primitives. Objects are treated in the above block
  7822. // Make sure the type is a math type
  7823. if( !(ctx->type.dataType.IsIntegerType() ||
  7824. ctx->type.dataType.IsUnsignedType() ||
  7825. ctx->type.dataType.IsFloatType() ||
  7826. ctx->type.dataType.IsDoubleType() ) )
  7827. {
  7828. Error(TXT_ILLEGAL_OPERATION, node);
  7829. return -1;
  7830. }
  7831. ProcessPropertyGetAccessor(ctx, node);
  7832. asCDataType to = ctx->type.dataType;
  7833. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  7834. if( ctx->type.dataType.IsUnsignedType() )
  7835. {
  7836. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7837. to = asCDataType::CreatePrimitive(ttInt8, false);
  7838. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7839. to = asCDataType::CreatePrimitive(ttInt16, false);
  7840. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7841. to = asCDataType::CreatePrimitive(ttInt, false);
  7842. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7843. to = asCDataType::CreatePrimitive(ttInt64, false);
  7844. else
  7845. {
  7846. Error(TXT_INVALID_TYPE, node);
  7847. return -1;
  7848. }
  7849. }
  7850. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7851. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7852. if( !ctx->type.isConstant )
  7853. {
  7854. ConvertToTempVariable(ctx);
  7855. asASSERT(!ctx->type.isLValue);
  7856. if( op == ttMinus )
  7857. {
  7858. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7859. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  7860. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7861. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  7862. else if( ctx->type.dataType.IsFloatType() )
  7863. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  7864. else if( ctx->type.dataType.IsDoubleType() )
  7865. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  7866. else
  7867. {
  7868. Error(TXT_ILLEGAL_OPERATION, node);
  7869. return -1;
  7870. }
  7871. return 0;
  7872. }
  7873. }
  7874. else
  7875. {
  7876. if( op == ttMinus )
  7877. {
  7878. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7879. ctx->type.intValue = -ctx->type.intValue;
  7880. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7881. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  7882. else if( ctx->type.dataType.IsFloatType() )
  7883. ctx->type.floatValue = -ctx->type.floatValue;
  7884. else if( ctx->type.dataType.IsDoubleType() )
  7885. ctx->type.doubleValue = -ctx->type.doubleValue;
  7886. else
  7887. {
  7888. Error(TXT_ILLEGAL_OPERATION, node);
  7889. return -1;
  7890. }
  7891. return 0;
  7892. }
  7893. }
  7894. }
  7895. else if( op == ttNot )
  7896. {
  7897. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7898. {
  7899. if( ctx->type.isConstant )
  7900. {
  7901. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  7902. return 0;
  7903. }
  7904. ProcessPropertyGetAccessor(ctx, node);
  7905. ConvertToTempVariable(ctx);
  7906. asASSERT(!ctx->type.isLValue);
  7907. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7908. }
  7909. else
  7910. {
  7911. Error(TXT_ILLEGAL_OPERATION, node);
  7912. return -1;
  7913. }
  7914. }
  7915. else if( op == ttBitNot )
  7916. {
  7917. ProcessPropertyGetAccessor(ctx, node);
  7918. asCDataType to = ctx->type.dataType;
  7919. if( ctx->type.dataType.IsIntegerType() )
  7920. {
  7921. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7922. to = asCDataType::CreatePrimitive(ttUInt8, false);
  7923. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7924. to = asCDataType::CreatePrimitive(ttUInt16, false);
  7925. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7926. to = asCDataType::CreatePrimitive(ttUInt, false);
  7927. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7928. to = asCDataType::CreatePrimitive(ttUInt64, false);
  7929. else
  7930. {
  7931. Error(TXT_INVALID_TYPE, node);
  7932. return -1;
  7933. }
  7934. }
  7935. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7936. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7937. if( ctx->type.dataType.IsUnsignedType() )
  7938. {
  7939. if( ctx->type.isConstant )
  7940. {
  7941. ctx->type.qwordValue = ~ctx->type.qwordValue;
  7942. return 0;
  7943. }
  7944. ConvertToTempVariable(ctx);
  7945. asASSERT(!ctx->type.isLValue);
  7946. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7947. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  7948. else
  7949. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  7950. }
  7951. else
  7952. {
  7953. Error(TXT_ILLEGAL_OPERATION, node);
  7954. return -1;
  7955. }
  7956. }
  7957. else if( op == ttInc || op == ttDec )
  7958. {
  7959. // Need a reference to the primitive that will be updated
  7960. // The result of this expression is the same reference as before
  7961. // Make sure the reference isn't a temporary variable
  7962. if( ctx->type.isTemporary )
  7963. {
  7964. Error(TXT_REF_IS_TEMP, node);
  7965. return -1;
  7966. }
  7967. if( ctx->type.dataType.IsReadOnly() )
  7968. {
  7969. Error(TXT_REF_IS_READ_ONLY, node);
  7970. return -1;
  7971. }
  7972. if( ctx->property_get || ctx->property_set )
  7973. {
  7974. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7975. return -1;
  7976. }
  7977. if( !ctx->type.isLValue )
  7978. {
  7979. Error(TXT_NOT_LVALUE, node);
  7980. return -1;
  7981. }
  7982. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7983. ConvertToReference(ctx);
  7984. else if( !ctx->type.dataType.IsReference() )
  7985. {
  7986. Error(TXT_NOT_VALID_REFERENCE, node);
  7987. return -1;
  7988. }
  7989. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7990. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7991. {
  7992. if( op == ttInc )
  7993. ctx->bc.Instr(asBC_INCi64);
  7994. else
  7995. ctx->bc.Instr(asBC_DECi64);
  7996. }
  7997. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  7998. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  7999. {
  8000. if( op == ttInc )
  8001. ctx->bc.Instr(asBC_INCi);
  8002. else
  8003. ctx->bc.Instr(asBC_DECi);
  8004. }
  8005. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  8006. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  8007. {
  8008. if( op == ttInc )
  8009. ctx->bc.Instr(asBC_INCi16);
  8010. else
  8011. ctx->bc.Instr(asBC_DECi16);
  8012. }
  8013. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  8014. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  8015. {
  8016. if( op == ttInc )
  8017. ctx->bc.Instr(asBC_INCi8);
  8018. else
  8019. ctx->bc.Instr(asBC_DECi8);
  8020. }
  8021. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  8022. {
  8023. if( op == ttInc )
  8024. ctx->bc.Instr(asBC_INCf);
  8025. else
  8026. ctx->bc.Instr(asBC_DECf);
  8027. }
  8028. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  8029. {
  8030. if( op == ttInc )
  8031. ctx->bc.Instr(asBC_INCd);
  8032. else
  8033. ctx->bc.Instr(asBC_DECd);
  8034. }
  8035. else
  8036. {
  8037. Error(TXT_ILLEGAL_OPERATION, node);
  8038. return -1;
  8039. }
  8040. }
  8041. else
  8042. {
  8043. // Unknown operator
  8044. asASSERT(false);
  8045. return -1;
  8046. }
  8047. return 0;
  8048. }
  8049. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  8050. {
  8051. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8052. {
  8053. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  8054. ctx->type.dataType.MakeReference(true);
  8055. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  8056. }
  8057. }
  8058. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  8059. {
  8060. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  8061. }
  8062. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  8063. {
  8064. if( engine->ep.propertyAccessorMode == 0 )
  8065. {
  8066. // Property accessors have been disabled by the application
  8067. return 0;
  8068. }
  8069. int getId = 0, setId = 0;
  8070. asCString getName = "get_" + name;
  8071. asCString setName = "set_" + name;
  8072. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  8073. if( ctx->type.dataType.IsObject() )
  8074. {
  8075. asASSERT( ns == 0 );
  8076. // Don't look for property accessors in script classes if the script
  8077. // property accessors have been disabled by the application
  8078. if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
  8079. engine->ep.propertyAccessorMode == 2 )
  8080. {
  8081. // Check if the object has any methods with the corresponding accessor name(s)
  8082. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8083. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8084. {
  8085. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8086. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  8087. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  8088. {
  8089. if( getId == 0 )
  8090. getId = ot->methods[n];
  8091. else
  8092. {
  8093. if( multipleGetFuncs.GetLength() == 0 )
  8094. multipleGetFuncs.PushLast(getId);
  8095. multipleGetFuncs.PushLast(ot->methods[n]);
  8096. }
  8097. }
  8098. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  8099. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  8100. {
  8101. if( setId == 0 )
  8102. setId = ot->methods[n];
  8103. else
  8104. {
  8105. if( multipleSetFuncs.GetLength() == 0 )
  8106. multipleSetFuncs.PushLast(setId);
  8107. multipleSetFuncs.PushLast(ot->methods[n]);
  8108. }
  8109. }
  8110. }
  8111. }
  8112. }
  8113. else
  8114. {
  8115. asASSERT( ns != 0 );
  8116. // Look for appropriate global functions.
  8117. asCArray<int> funcs;
  8118. asUINT n;
  8119. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  8120. for( n = 0; n < funcs.GetLength(); n++ )
  8121. {
  8122. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  8123. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  8124. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  8125. {
  8126. if( getId == 0 )
  8127. getId = funcs[n];
  8128. else
  8129. {
  8130. if( multipleGetFuncs.GetLength() == 0 )
  8131. multipleGetFuncs.PushLast(getId);
  8132. multipleGetFuncs.PushLast(funcs[n]);
  8133. }
  8134. }
  8135. }
  8136. funcs.SetLength(0);
  8137. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  8138. for( n = 0; n < funcs.GetLength(); n++ )
  8139. {
  8140. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  8141. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  8142. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  8143. {
  8144. if( setId == 0 )
  8145. setId = funcs[n];
  8146. else
  8147. {
  8148. if( multipleSetFuncs.GetLength() == 0 )
  8149. multipleSetFuncs.PushLast(getId);
  8150. multipleSetFuncs.PushLast(funcs[n]);
  8151. }
  8152. }
  8153. }
  8154. }
  8155. bool isConst = false;
  8156. if( ctx->type.dataType.IsObjectHandle() )
  8157. isConst = ctx->type.dataType.IsHandleToConst();
  8158. else
  8159. isConst = ctx->type.dataType.IsReadOnly();
  8160. // Check for multiple matches
  8161. if( multipleGetFuncs.GetLength() > 0 )
  8162. {
  8163. // Filter the list by constness
  8164. FilterConst(multipleGetFuncs, !isConst);
  8165. if( multipleGetFuncs.GetLength() > 1 )
  8166. {
  8167. asCString str;
  8168. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  8169. Error(str, node);
  8170. PrintMatchingFuncs(multipleGetFuncs, node);
  8171. return -1;
  8172. }
  8173. else
  8174. {
  8175. // The id may have changed
  8176. getId = multipleGetFuncs[0];
  8177. }
  8178. }
  8179. if( multipleSetFuncs.GetLength() > 0 )
  8180. {
  8181. // Filter the list by constness
  8182. FilterConst(multipleSetFuncs, !isConst);
  8183. if( multipleSetFuncs.GetLength() > 1 )
  8184. {
  8185. asCString str;
  8186. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  8187. Error(str, node);
  8188. PrintMatchingFuncs(multipleSetFuncs, node);
  8189. return -1;
  8190. }
  8191. else
  8192. {
  8193. // The id may have changed
  8194. setId = multipleSetFuncs[0];
  8195. }
  8196. }
  8197. // Check for type compatibility between get and set accessor
  8198. if( getId && setId )
  8199. {
  8200. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  8201. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  8202. // It is permitted for a getter to return a handle and the setter to take a reference
  8203. int idx = (arg?1:0);
  8204. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  8205. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  8206. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  8207. {
  8208. asCString str;
  8209. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  8210. Error(str, node);
  8211. asCArray<int> funcs;
  8212. funcs.PushLast(getId);
  8213. funcs.PushLast(setId);
  8214. PrintMatchingFuncs(funcs, node);
  8215. return -1;
  8216. }
  8217. }
  8218. // Check if we are within one of the accessors
  8219. int realGetId = getId;
  8220. int realSetId = setId;
  8221. if( outFunc->objectType && isThisAccess )
  8222. {
  8223. // The property accessors would be virtual functions, so we need to find the real implementation
  8224. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  8225. if( getFunc &&
  8226. getFunc->funcType == asFUNC_VIRTUAL &&
  8227. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  8228. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  8229. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  8230. if( setFunc &&
  8231. setFunc->funcType == asFUNC_VIRTUAL &&
  8232. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  8233. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  8234. }
  8235. // Avoid recursive call, by not treating this as a property accessor call.
  8236. // This will also allow having the real property with the same name as the accessors.
  8237. if( (isThisAccess || outFunc->objectType == 0) &&
  8238. ((realGetId && realGetId == outFunc->id) ||
  8239. (realSetId && realSetId == outFunc->id)) )
  8240. {
  8241. getId = 0;
  8242. setId = 0;
  8243. }
  8244. // Check if the application has disabled script written property accessors
  8245. if( engine->ep.propertyAccessorMode == 1 )
  8246. {
  8247. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  8248. getId = 0;
  8249. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  8250. setId = 0;
  8251. }
  8252. if( getId || setId )
  8253. {
  8254. // Property accessors were found, but we don't know which is to be used yet, so
  8255. // we just prepare the bytecode for the method call, and then store the function ids
  8256. // so that the right one can be used when we get there.
  8257. ctx->property_get = getId;
  8258. ctx->property_set = setId;
  8259. if( ctx->type.dataType.IsObject() )
  8260. {
  8261. // If the object is read-only then we need to remember that
  8262. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  8263. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  8264. ctx->property_const = true;
  8265. else
  8266. ctx->property_const = false;
  8267. // If the object is a handle then we need to remember that
  8268. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  8269. ctx->property_ref = ctx->type.dataType.IsReference();
  8270. }
  8271. // The setter's parameter type is used as the property type,
  8272. // unless only the getter is available
  8273. asCDataType dt;
  8274. if( setId )
  8275. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  8276. else
  8277. dt = builder->GetFunctionDescription(getId)->returnType;
  8278. // Just change the type, the context must still maintain information
  8279. // about previous variable offset and the indicator of temporary variable.
  8280. int offset = ctx->type.stackOffset;
  8281. bool isTemp = ctx->type.isTemporary;
  8282. ctx->type.Set(dt);
  8283. ctx->type.stackOffset = (short)offset;
  8284. ctx->type.isTemporary = isTemp;
  8285. ctx->exprNode = node;
  8286. // Store the argument for later use
  8287. if( arg )
  8288. {
  8289. ctx->property_arg = asNEW(asSExprContext)(engine);
  8290. if( ctx->property_arg == 0 )
  8291. {
  8292. // Out of memory
  8293. return -1;
  8294. }
  8295. MergeExprBytecodeAndType(ctx->property_arg, arg);
  8296. }
  8297. return 1;
  8298. }
  8299. // No accessor was found
  8300. return 0;
  8301. }
  8302. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  8303. {
  8304. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  8305. if( !ctx->property_set )
  8306. {
  8307. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  8308. return -1;
  8309. }
  8310. asCTypeInfo objType = ctx->type;
  8311. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  8312. // Make sure the arg match the property
  8313. asCArray<int> funcs;
  8314. funcs.PushLast(ctx->property_set);
  8315. asCArray<asSExprContext *> args;
  8316. if( ctx->property_arg )
  8317. args.PushLast(ctx->property_arg);
  8318. args.PushLast(arg);
  8319. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  8320. if( funcs.GetLength() == 0 )
  8321. {
  8322. // MatchFunctions already reported the error
  8323. if( ctx->property_arg )
  8324. {
  8325. asDELETE(ctx->property_arg, asSExprContext);
  8326. ctx->property_arg = 0;
  8327. }
  8328. return -1;
  8329. }
  8330. if( func->objectType )
  8331. {
  8332. // Setup the context with the original type so the method call gets built correctly
  8333. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8334. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8335. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8336. // Don't allow the call if the object is read-only and the property accessor is not const
  8337. if( ctx->property_const && !func->isReadOnly )
  8338. {
  8339. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  8340. asCArray<int> funcs;
  8341. funcs.PushLast(ctx->property_set);
  8342. PrintMatchingFuncs(funcs, node);
  8343. }
  8344. }
  8345. // Call the accessor
  8346. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  8347. if( func->objectType )
  8348. {
  8349. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8350. if( !objType.isTemporary ||
  8351. !ctx->type.dataType.IsReference() ||
  8352. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8353. {
  8354. // As the method didn't return a reference to a member
  8355. // we can safely release the original object now
  8356. ReleaseTemporaryVariable(objType, &ctx->bc);
  8357. }
  8358. }
  8359. ctx->property_get = 0;
  8360. ctx->property_set = 0;
  8361. if( ctx->property_arg )
  8362. {
  8363. asDELETE(ctx->property_arg, asSExprContext);
  8364. ctx->property_arg = 0;
  8365. }
  8366. return 0;
  8367. }
  8368. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  8369. {
  8370. // If no property accessor has been prepared then don't do anything
  8371. if( !ctx->property_get && !ctx->property_set )
  8372. return;
  8373. if( !ctx->property_get )
  8374. {
  8375. // Raise error on missing accessor
  8376. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  8377. ctx->type.SetDummy();
  8378. return;
  8379. }
  8380. asCTypeInfo objType = ctx->type;
  8381. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  8382. // Make sure the arg match the property
  8383. asCArray<int> funcs;
  8384. funcs.PushLast(ctx->property_get);
  8385. asCArray<asSExprContext *> args;
  8386. if( ctx->property_arg )
  8387. args.PushLast(ctx->property_arg);
  8388. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  8389. if( funcs.GetLength() == 0 )
  8390. {
  8391. // MatchFunctions already reported the error
  8392. if( ctx->property_arg )
  8393. {
  8394. asDELETE(ctx->property_arg, asSExprContext);
  8395. ctx->property_arg = 0;
  8396. }
  8397. ctx->type.SetDummy();
  8398. return;
  8399. }
  8400. if( func->objectType )
  8401. {
  8402. // Setup the context with the original type so the method call gets built correctly
  8403. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8404. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8405. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8406. // Don't allow the call if the object is read-only and the property accessor is not const
  8407. if( ctx->property_const && !func->isReadOnly )
  8408. {
  8409. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  8410. asCArray<int> funcs;
  8411. funcs.PushLast(ctx->property_get);
  8412. PrintMatchingFuncs(funcs, node);
  8413. }
  8414. }
  8415. // Call the accessor
  8416. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  8417. if( func->objectType )
  8418. {
  8419. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8420. // If the method returned a reference, then we can't release the original
  8421. // object yet, because the reference may be to a member of it
  8422. if( !objType.isTemporary ||
  8423. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8424. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8425. {
  8426. // As the method didn't return a reference to a member
  8427. // we can safely release the original object now
  8428. ReleaseTemporaryVariable(objType, &ctx->bc);
  8429. }
  8430. }
  8431. ctx->property_get = 0;
  8432. ctx->property_set = 0;
  8433. if( ctx->property_arg )
  8434. {
  8435. asDELETE(ctx->property_arg, asSExprContext);
  8436. ctx->property_arg = 0;
  8437. }
  8438. }
  8439. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  8440. {
  8441. // Don't allow any postfix operators on expressions that take address of class method
  8442. if( ctx->IsClassMethod() )
  8443. {
  8444. Error(TXT_INVALID_OP_ON_METHOD, node);
  8445. return -1;
  8446. }
  8447. // Don't allow any operators on void expressions
  8448. if( ctx->type.IsVoidExpression() )
  8449. {
  8450. Error(TXT_VOID_CANT_BE_OPERAND, node);
  8451. return -1;
  8452. }
  8453. // Check if the variable is initialized (if it indeed is a variable)
  8454. IsVariableInitialized(&ctx->type, node);
  8455. int op = node->tokenType;
  8456. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  8457. {
  8458. const char *opName = 0;
  8459. switch( op )
  8460. {
  8461. case ttInc: opName = "opPostInc"; break;
  8462. case ttDec: opName = "opPostDec"; break;
  8463. }
  8464. if( opName )
  8465. {
  8466. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  8467. ProcessPropertyGetAccessor(ctx, node);
  8468. // Is it a const value?
  8469. bool isConst = false;
  8470. if( ctx->type.dataType.IsObjectHandle() )
  8471. isConst = ctx->type.dataType.IsHandleToConst();
  8472. else
  8473. isConst = ctx->type.dataType.IsReadOnly();
  8474. // 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
  8475. // Find the correct method
  8476. asCArray<int> funcs;
  8477. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8478. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8479. {
  8480. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8481. if( func->name == opName &&
  8482. func->parameterTypes.GetLength() == 0 &&
  8483. (!isConst || func->isReadOnly) )
  8484. {
  8485. funcs.PushLast(func->id);
  8486. }
  8487. }
  8488. // Did we find the method?
  8489. if( funcs.GetLength() == 1 )
  8490. {
  8491. asCTypeInfo objType = ctx->type;
  8492. asCArray<asSExprContext *> args;
  8493. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  8494. ReleaseTemporaryVariable(objType, &ctx->bc);
  8495. return 0;
  8496. }
  8497. else if( funcs.GetLength() == 0 )
  8498. {
  8499. asCString str;
  8500. str = asCString(opName) + "()";
  8501. if( isConst )
  8502. str += " const";
  8503. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  8504. Error(str, node);
  8505. ctx->type.SetDummy();
  8506. return -1;
  8507. }
  8508. else if( funcs.GetLength() > 1 )
  8509. {
  8510. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8511. PrintMatchingFuncs(funcs, node);
  8512. ctx->type.SetDummy();
  8513. return -1;
  8514. }
  8515. }
  8516. }
  8517. else if( op == ttInc || op == ttDec )
  8518. {
  8519. // Make sure the reference isn't a temporary variable
  8520. if( ctx->type.isTemporary )
  8521. {
  8522. Error(TXT_REF_IS_TEMP, node);
  8523. return -1;
  8524. }
  8525. if( ctx->type.dataType.IsReadOnly() )
  8526. {
  8527. Error(TXT_REF_IS_READ_ONLY, node);
  8528. return -1;
  8529. }
  8530. if( ctx->property_get || ctx->property_set )
  8531. {
  8532. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  8533. return -1;
  8534. }
  8535. if( !ctx->type.isLValue )
  8536. {
  8537. Error(TXT_NOT_LVALUE, node);
  8538. return -1;
  8539. }
  8540. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8541. ConvertToReference(ctx);
  8542. else if( !ctx->type.dataType.IsReference() )
  8543. {
  8544. Error(TXT_NOT_VALID_REFERENCE, node);
  8545. return -1;
  8546. }
  8547. // Copy the value to a temp before changing it
  8548. ConvertToTempVariable(ctx);
  8549. asASSERT(!ctx->type.isLValue);
  8550. // Increment the value pointed to by the reference still in the register
  8551. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  8552. if( ctx->type.dataType.IsDoubleType() )
  8553. {
  8554. iInc = asBC_INCd;
  8555. iDec = asBC_DECd;
  8556. }
  8557. else if( ctx->type.dataType.IsFloatType() )
  8558. {
  8559. iInc = asBC_INCf;
  8560. iDec = asBC_DECf;
  8561. }
  8562. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  8563. {
  8564. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  8565. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  8566. {
  8567. iInc = asBC_INCi16;
  8568. iDec = asBC_DECi16;
  8569. }
  8570. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  8571. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  8572. {
  8573. iInc = asBC_INCi8;
  8574. iDec = asBC_DECi8;
  8575. }
  8576. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  8577. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  8578. {
  8579. iInc = asBC_INCi64;
  8580. iDec = asBC_DECi64;
  8581. }
  8582. }
  8583. else
  8584. {
  8585. Error(TXT_ILLEGAL_OPERATION, node);
  8586. return -1;
  8587. }
  8588. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  8589. }
  8590. else if( op == ttDot )
  8591. {
  8592. if( node->firstChild->nodeType == snIdentifier )
  8593. {
  8594. ProcessPropertyGetAccessor(ctx, node);
  8595. // Get the property name
  8596. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  8597. if( ctx->type.dataType.IsObject() )
  8598. {
  8599. // We need to look for get/set property accessors.
  8600. // If found, the context stores information on the get/set accessors
  8601. // until it is known which is to be used.
  8602. int r = 0;
  8603. if( node->next && node->next->tokenType == ttOpenBracket )
  8604. {
  8605. // The property accessor should take an index arg
  8606. asSExprContext dummyArg(engine);
  8607. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  8608. }
  8609. if( r == 0 )
  8610. r = FindPropertyAccessor(name, ctx, node, 0);
  8611. if( r != 0 )
  8612. return r;
  8613. if( !ctx->type.dataType.IsPrimitive() )
  8614. Dereference(ctx, true);
  8615. if( ctx->type.dataType.IsObjectHandle() )
  8616. {
  8617. // Convert the handle to a normal object
  8618. asCDataType dt = ctx->type.dataType;
  8619. dt.MakeHandle(false);
  8620. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  8621. // The handle may not have been an lvalue, but the dereferenced object is
  8622. ctx->type.isLValue = true;
  8623. }
  8624. bool isConst = ctx->type.dataType.IsReadOnly();
  8625. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  8626. if( prop )
  8627. {
  8628. // Is the property access allowed?
  8629. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  8630. {
  8631. asCString msg;
  8632. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8633. Error(msg, node);
  8634. }
  8635. // Put the offset on the stack
  8636. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  8637. if( prop->type.IsReference() )
  8638. ctx->bc.Instr(asBC_RDSPtr);
  8639. // Reference to primitive must be stored in the temp register
  8640. if( prop->type.IsPrimitive() )
  8641. {
  8642. ctx->bc.Instr(asBC_PopRPtr);
  8643. }
  8644. // Keep information about temporary variables as deferred expression
  8645. if( ctx->type.isTemporary )
  8646. {
  8647. // Add the release of this reference, as a deferred expression
  8648. asSDeferredParam deferred;
  8649. deferred.origExpr = 0;
  8650. deferred.argInOutFlags = asTM_INREF;
  8651. deferred.argNode = 0;
  8652. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8653. ctx->deferredParams.PushLast(deferred);
  8654. }
  8655. // Set the new type and make sure it is not treated as a variable anymore
  8656. ctx->type.dataType = prop->type;
  8657. ctx->type.dataType.MakeReference(true);
  8658. ctx->type.isVariable = false;
  8659. ctx->type.isTemporary = false;
  8660. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  8661. {
  8662. // Objects that are members are not references
  8663. ctx->type.dataType.MakeReference(false);
  8664. }
  8665. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  8666. }
  8667. else
  8668. {
  8669. // If the name is not a property, the compiler must check if the name matches
  8670. // a method, which can be used for constructing delegates
  8671. asIScriptFunction *func = 0;
  8672. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8673. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8674. {
  8675. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  8676. {
  8677. func = engine->scriptFunctions[ot->methods[n]];
  8678. break;
  8679. }
  8680. }
  8681. if( func )
  8682. {
  8683. // An object method was found. Keep the name of the method in the expression, but
  8684. // don't actually modify the bytecode at this point since it is not yet known what
  8685. // the method will be used for, or even what overloaded method should be used.
  8686. ctx->methodName = name;
  8687. }
  8688. else
  8689. {
  8690. asCString str;
  8691. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8692. Error(str, node);
  8693. return -1;
  8694. }
  8695. }
  8696. }
  8697. else
  8698. {
  8699. asCString str;
  8700. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8701. Error(str, node);
  8702. return -1;
  8703. }
  8704. }
  8705. else
  8706. {
  8707. // Make sure it is an object we are accessing
  8708. if( !ctx->type.dataType.IsObject() )
  8709. {
  8710. asCString str;
  8711. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  8712. Error(str, node);
  8713. return -1;
  8714. }
  8715. // Process the get property accessor
  8716. ProcessPropertyGetAccessor(ctx, node);
  8717. bool isConst = false;
  8718. if( ctx->type.dataType.IsObjectHandle() )
  8719. isConst = ctx->type.dataType.IsHandleToConst();
  8720. else
  8721. isConst = ctx->type.dataType.IsReadOnly();
  8722. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  8723. asCTypeInfo objType = ctx->type;
  8724. // Compile function call
  8725. int r = CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  8726. if( r < 0 ) return r;
  8727. // If the method returned a reference, then we can't release the original
  8728. // object yet, because the reference may be to a member of it
  8729. if( !objType.isTemporary ||
  8730. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8731. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8732. {
  8733. // As the method didn't return a reference to a member
  8734. // we can safely release the original object now
  8735. ReleaseTemporaryVariable(objType, &ctx->bc);
  8736. }
  8737. }
  8738. }
  8739. else if( op == ttOpenBracket )
  8740. {
  8741. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  8742. // then we should use that instead of processing it now. If the argument has already been
  8743. // evaluated, then we should process the property accessor as a get access now as the new
  8744. // index operator is on the result of that accessor.
  8745. asCString propertyName;
  8746. asSNameSpace *ns = 0;
  8747. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  8748. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  8749. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  8750. {
  8751. // Determine the name of the property accessor
  8752. asCScriptFunction *func = 0;
  8753. if( ctx->property_get )
  8754. func = builder->GetFunctionDescription(ctx->property_get);
  8755. else
  8756. func = builder->GetFunctionDescription(ctx->property_set);
  8757. propertyName = func->GetName();
  8758. propertyName = propertyName.SubString(4);
  8759. // Set the original type of the expression so we can re-evaluate the property accessor
  8760. if( func->objectType )
  8761. {
  8762. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8763. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8764. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8765. }
  8766. else
  8767. {
  8768. // Store the namespace where the function is declared
  8769. // so the same function can be found later
  8770. ctx->type.SetDummy();
  8771. ns = func->nameSpace;
  8772. }
  8773. ctx->property_get = ctx->property_set = 0;
  8774. if( ctx->property_arg )
  8775. {
  8776. asDELETE(ctx->property_arg, asSExprContext);
  8777. ctx->property_arg = 0;
  8778. }
  8779. }
  8780. else
  8781. {
  8782. if( !ctx->type.dataType.IsObject() )
  8783. {
  8784. asCString str;
  8785. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8786. Error(str, node);
  8787. return -1;
  8788. }
  8789. ProcessPropertyGetAccessor(ctx, node);
  8790. }
  8791. Dereference(ctx, true);
  8792. // Compile the expression
  8793. asSExprContext expr(engine);
  8794. CompileAssignment(node->firstChild, &expr);
  8795. // Check for the existence of the opIndex method
  8796. asSExprContext lctx(engine);
  8797. MergeExprBytecodeAndType(&lctx, ctx);
  8798. int r = 0;
  8799. if( propertyName == "" )
  8800. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  8801. if( r == 0 )
  8802. {
  8803. // Check for accessors methods for the opIndex
  8804. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node, ns);
  8805. if( r == 0 )
  8806. {
  8807. asCString str;
  8808. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8809. Error(str, node);
  8810. return -1;
  8811. }
  8812. else if( r < 0 )
  8813. return -1;
  8814. MergeExprBytecodeAndType(ctx, &lctx);
  8815. }
  8816. }
  8817. else if( op == ttOpenParanthesis )
  8818. {
  8819. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  8820. // Make sure the expression is a funcdef
  8821. if( !ctx->type.dataType.GetFuncDef() )
  8822. {
  8823. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  8824. return -1;
  8825. }
  8826. // Compile arguments
  8827. asCArray<asSExprContext *> args;
  8828. if( CompileArgumentList(node->lastChild, args) >= 0 )
  8829. {
  8830. // Match arguments with the funcdef
  8831. asCArray<int> funcs;
  8832. funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
  8833. MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf());
  8834. if( funcs.GetLength() != 1 )
  8835. {
  8836. // The error was reported by MatchFunctions()
  8837. // Dummy value
  8838. ctx->type.SetDummy();
  8839. }
  8840. else
  8841. {
  8842. int r = asSUCCESS;
  8843. // Add the default values for arguments not explicitly supplied
  8844. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  8845. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  8846. r = CompileDefaultArgs(node, args, func);
  8847. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8848. // is it enough to make sure it is in a local variable?
  8849. // For function pointer we must guarantee that the function is safe, i.e.
  8850. // by first storing the function pointer in a local variable (if it isn't already in one)
  8851. if( r == asSUCCESS )
  8852. {
  8853. Dereference(ctx, true);
  8854. if( !ctx->type.isVariable )
  8855. ConvertToVariable(ctx);
  8856. else
  8857. {
  8858. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  8859. ctx->bc.Instr(asBC_PopPtr);
  8860. }
  8861. asCTypeInfo t = ctx->type;
  8862. MakeFunctionCall(ctx, funcs[0], 0, args, node, false, 0, ctx->type.stackOffset);
  8863. ReleaseTemporaryVariable(t, &ctx->bc);
  8864. }
  8865. }
  8866. }
  8867. else
  8868. ctx->type.SetDummy();
  8869. // Cleanup
  8870. for( asUINT n = 0; n < args.GetLength(); n++ )
  8871. if( args[n] )
  8872. {
  8873. asDELETE(args[n],asSExprContext);
  8874. }
  8875. }
  8876. return 0;
  8877. }
  8878. int asCCompiler::GetPrecedence(asCScriptNode *op)
  8879. {
  8880. // x * y, x / y, x % y
  8881. // x + y, x - y
  8882. // x <= y, x < y, x >= y, x > y
  8883. // x = =y, x != y, x xor y, x is y, x !is y
  8884. // x and y
  8885. // x or y
  8886. // The following are not used in this function,
  8887. // but should have lower precedence than the above
  8888. // x ? y : z
  8889. // x = y
  8890. // The expression term have the highest precedence
  8891. if( op->nodeType == snExprTerm )
  8892. return 1;
  8893. // Evaluate operators by token
  8894. int tokenType = op->tokenType;
  8895. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  8896. return 0;
  8897. if( tokenType == ttPlus || tokenType == ttMinus )
  8898. return -1;
  8899. if( tokenType == ttBitShiftLeft ||
  8900. tokenType == ttBitShiftRight ||
  8901. tokenType == ttBitShiftRightArith )
  8902. return -2;
  8903. if( tokenType == ttAmp )
  8904. return -3;
  8905. if( tokenType == ttBitXor )
  8906. return -4;
  8907. if( tokenType == ttBitOr )
  8908. return -5;
  8909. if( tokenType == ttLessThanOrEqual ||
  8910. tokenType == ttLessThan ||
  8911. tokenType == ttGreaterThanOrEqual ||
  8912. tokenType == ttGreaterThan )
  8913. return -6;
  8914. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  8915. return -7;
  8916. if( tokenType == ttAnd )
  8917. return -8;
  8918. if( tokenType == ttOr )
  8919. return -9;
  8920. // Unknown operator
  8921. asASSERT(false);
  8922. return 0;
  8923. }
  8924. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  8925. {
  8926. matches.SetLength(0);
  8927. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  8928. {
  8929. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  8930. // Does the function have arguments enough?
  8931. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  8932. continue;
  8933. // void expressions can match any out parameter, but nothing else
  8934. if( argExpr->type.IsVoidExpression() )
  8935. {
  8936. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  8937. matches.PushLast(asSOverloadCandidate(funcs[n], 0));
  8938. continue;
  8939. }
  8940. // Can we make the match by implicit conversion?
  8941. asSExprContext ti(engine);
  8942. ti.type = argExpr->type;
  8943. ti.methodName = argExpr->methodName;
  8944. if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  8945. asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  8946. // If the function parameter is an inout-reference then it must not be possible to call the
  8947. // function with an incorrect argument type, even though the type can normally be converted.
  8948. if( desc->parameterTypes[paramNum].IsReference() &&
  8949. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  8950. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  8951. {
  8952. // Observe, that the below checks are only necessary for when unsafe references have been
  8953. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  8954. // for these value types.
  8955. // Don't allow a primitive to be converted to a reference of another primitive type
  8956. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  8957. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  8958. {
  8959. asASSERT( engine->ep.allowUnsafeReferences );
  8960. continue;
  8961. }
  8962. // Don't allow an enum to be converted to a reference of another enum type
  8963. if( desc->parameterTypes[paramNum].IsEnumType() &&
  8964. desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
  8965. {
  8966. asASSERT( engine->ep.allowUnsafeReferences );
  8967. continue;
  8968. }
  8969. // Don't allow a non-handle expression to be converted to a reference to a handle
  8970. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  8971. !argExpr->type.dataType.IsObjectHandle() )
  8972. {
  8973. asASSERT( engine->ep.allowUnsafeReferences );
  8974. continue;
  8975. }
  8976. // Don't allow a value type to be converted
  8977. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  8978. (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
  8979. {
  8980. asASSERT( engine->ep.allowUnsafeReferences );
  8981. continue;
  8982. }
  8983. }
  8984. // How well does the argument match the function parameter?
  8985. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  8986. matches.PushLast(asSOverloadCandidate(funcs[n], cost));
  8987. }
  8988. return (asUINT)matches.GetLength();
  8989. }
  8990. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  8991. {
  8992. // Reference parameters whose value won't be used don't evaluate the expression
  8993. if( paramType->IsReference() && !(refType & asTM_INREF) )
  8994. {
  8995. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  8996. asSExprContext *orig = asNEW(asSExprContext)(engine);
  8997. if( orig == 0 )
  8998. {
  8999. // Out of memory
  9000. return;
  9001. }
  9002. MergeExprBytecodeAndType(orig, arg);
  9003. arg->origExpr = orig;
  9004. }
  9005. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  9006. // arg still holds the original expression for output parameters
  9007. ctx->bc.AddCode(&arg->bc);
  9008. }
  9009. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9010. {
  9011. DetermineSingleFunc(lctx, node);
  9012. DetermineSingleFunc(rctx, node);
  9013. ctx->exprNode = node;
  9014. // What type of operator is it?
  9015. int token = node->tokenType;
  9016. if( token == ttUnrecognizedToken )
  9017. {
  9018. // This happens when the compiler is inferring an assignment
  9019. // operation from another action, for example in preparing a value
  9020. // as a function argument
  9021. token = ttAssignment;
  9022. }
  9023. // boolean operators are not overloadable
  9024. if( token == ttAnd ||
  9025. token == ttOr ||
  9026. token == ttXor )
  9027. return false;
  9028. // Dual operators can also be implemented as class methods
  9029. if( token == ttEqual ||
  9030. token == ttNotEqual )
  9031. {
  9032. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9033. // Find the matching opEquals method
  9034. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9035. if( r == 0 )
  9036. {
  9037. // Try again by switching the order of the operands
  9038. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9039. }
  9040. if( r == 1 )
  9041. {
  9042. if( token == ttNotEqual )
  9043. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9044. // Success, don't continue
  9045. return true;
  9046. }
  9047. else if( r < 0 )
  9048. {
  9049. // Compiler error, don't continue
  9050. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9051. return true;
  9052. }
  9053. }
  9054. if( token == ttEqual ||
  9055. token == ttNotEqual ||
  9056. token == ttLessThan ||
  9057. token == ttLessThanOrEqual ||
  9058. token == ttGreaterThan ||
  9059. token == ttGreaterThanOrEqual )
  9060. {
  9061. bool swappedOrder = false;
  9062. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9063. // Find the matching opCmp method
  9064. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  9065. if( r == 0 )
  9066. {
  9067. // Try again by switching the order of the operands
  9068. swappedOrder = true;
  9069. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  9070. }
  9071. if( r == 1 )
  9072. {
  9073. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9074. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  9075. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  9076. if( token == ttEqual )
  9077. ctx->bc.Instr(asBC_TZ);
  9078. else if( token == ttNotEqual )
  9079. ctx->bc.Instr(asBC_TNZ);
  9080. else if( (token == ttLessThan && !swappedOrder) ||
  9081. (token == ttGreaterThan && swappedOrder) )
  9082. ctx->bc.Instr(asBC_TS);
  9083. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  9084. (token == ttGreaterThanOrEqual && swappedOrder) )
  9085. ctx->bc.Instr(asBC_TNP);
  9086. else if( (token == ttGreaterThan && !swappedOrder) ||
  9087. (token == ttLessThan && swappedOrder) )
  9088. ctx->bc.Instr(asBC_TP);
  9089. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  9090. (token == ttLessThanOrEqual && swappedOrder) )
  9091. ctx->bc.Instr(asBC_TNS);
  9092. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9093. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  9094. // Success, don't continue
  9095. return true;
  9096. }
  9097. else if( r < 0 )
  9098. {
  9099. // Compiler error, don't continue
  9100. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9101. return true;
  9102. }
  9103. }
  9104. // The rest of the operators are not commutative, and doesn't require specific return type
  9105. const char *op = 0, *op_r = 0;
  9106. switch( token )
  9107. {
  9108. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  9109. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  9110. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  9111. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  9112. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  9113. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  9114. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  9115. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  9116. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  9117. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  9118. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  9119. }
  9120. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  9121. if( op && op_r )
  9122. {
  9123. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9124. // Find the matching operator method
  9125. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  9126. if( r == 0 )
  9127. {
  9128. // Try again by switching the order of the operands, and using the reversed operator
  9129. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  9130. }
  9131. if( r == 1 )
  9132. {
  9133. // Success, don't continue
  9134. return true;
  9135. }
  9136. else if( r < 0 )
  9137. {
  9138. // Compiler error, don't continue
  9139. ctx->type.SetDummy();
  9140. return true;
  9141. }
  9142. }
  9143. // Assignment operators
  9144. op = 0;
  9145. switch( token )
  9146. {
  9147. case ttAssignment: op = "opAssign"; break;
  9148. case ttAddAssign: op = "opAddAssign"; break;
  9149. case ttSubAssign: op = "opSubAssign"; break;
  9150. case ttMulAssign: op = "opMulAssign"; break;
  9151. case ttDivAssign: op = "opDivAssign"; break;
  9152. case ttModAssign: op = "opModAssign"; break;
  9153. case ttOrAssign: op = "opOrAssign"; break;
  9154. case ttAndAssign: op = "opAndAssign"; break;
  9155. case ttXorAssign: op = "opXorAssign"; break;
  9156. case ttShiftLeftAssign: op = "opShlAssign"; break;
  9157. case ttShiftRightLAssign: op = "opShrAssign"; break;
  9158. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  9159. }
  9160. if( op )
  9161. {
  9162. if( builder->engine->ep.disallowValueAssignForRefType &&
  9163. lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  9164. {
  9165. if( token == ttAssignment )
  9166. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  9167. else
  9168. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  9169. // Set a dummy output
  9170. ctx->type.Set(lctx->type.dataType);
  9171. return true;
  9172. }
  9173. // TODO: Shouldn't accept const lvalue with the assignment operators
  9174. // Find the matching operator method
  9175. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  9176. if( r == 1 )
  9177. {
  9178. // Success, don't continue
  9179. return true;
  9180. }
  9181. else if( r < 0 )
  9182. {
  9183. // Compiler error, don't continue
  9184. ctx->type.SetDummy();
  9185. return true;
  9186. }
  9187. }
  9188. // No suitable operator was found
  9189. return false;
  9190. }
  9191. // Returns negative on compile error
  9192. // zero on no matching operator
  9193. // one on matching operator
  9194. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  9195. {
  9196. // Find the matching method
  9197. if( lctx->type.dataType.IsObject() &&
  9198. (!lctx->type.isExplicitHandle ||
  9199. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  9200. {
  9201. asUINT n;
  9202. // Is the left value a const?
  9203. bool isConst = false;
  9204. if( lctx->type.dataType.IsObjectHandle() )
  9205. isConst = lctx->type.dataType.IsHandleToConst();
  9206. else
  9207. isConst = lctx->type.dataType.IsReadOnly();
  9208. asCArray<int> funcs;
  9209. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  9210. for( n = 0; n < ot->methods.GetLength(); n++ )
  9211. {
  9212. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9213. if( func->name == methodName &&
  9214. (!specificReturn || func->returnType == returnType) &&
  9215. func->parameterTypes.GetLength() == 1 &&
  9216. (!isConst || func->isReadOnly) )
  9217. {
  9218. // Make sure the method is accessible by the module
  9219. if( builder->module->accessMask & func->accessMask )
  9220. {
  9221. funcs.PushLast(func->id);
  9222. }
  9223. }
  9224. }
  9225. // Which is the best matching function?
  9226. asCArray<asSOverloadCandidate> tempFuncs;
  9227. MatchArgument(funcs, tempFuncs, rctx, 0);
  9228. // Find the lowest cost operator(s)
  9229. asCArray<int> ops;
  9230. asUINT bestCost = asUINT(-1);
  9231. for( n = 0; n < tempFuncs.GetLength(); ++n )
  9232. {
  9233. asUINT cost = tempFuncs[n].cost;
  9234. if( cost < bestCost )
  9235. {
  9236. ops.SetLength(0);
  9237. bestCost = cost;
  9238. }
  9239. if( cost == bestCost )
  9240. ops.PushLast(tempFuncs[n].funcId);
  9241. }
  9242. // If the object is not const, then we need to prioritize non-const methods
  9243. if( !isConst )
  9244. FilterConst(ops);
  9245. // Did we find an operator?
  9246. if( ops.GetLength() == 1 )
  9247. {
  9248. // Process the lctx expression as get accessor
  9249. ProcessPropertyGetAccessor(lctx, node);
  9250. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  9251. asCTypeInfo objType = lctx->type;
  9252. asCArray<asSExprContext *> args;
  9253. args.PushLast(rctx);
  9254. MergeExprBytecode(ctx, lctx);
  9255. ctx->type = lctx->type;
  9256. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  9257. // If the method returned a reference, then we can't release the original
  9258. // object yet, because the reference may be to a member of it
  9259. if( !objType.isTemporary ||
  9260. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  9261. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  9262. {
  9263. // As the index operator didn't return a reference to a
  9264. // member we can release the original object now
  9265. ReleaseTemporaryVariable(objType, &ctx->bc);
  9266. }
  9267. // Found matching operator
  9268. return 1;
  9269. }
  9270. else if( ops.GetLength() > 1 )
  9271. {
  9272. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9273. PrintMatchingFuncs(ops, node);
  9274. ctx->type.SetDummy();
  9275. // Compiler error
  9276. return -1;
  9277. }
  9278. }
  9279. // No matching operator
  9280. return 0;
  9281. }
  9282. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  9283. {
  9284. if( objectType )
  9285. {
  9286. Dereference(ctx, true);
  9287. // This following warning was removed as there may be valid reasons
  9288. // for calling non-const methods on temporary objects, and we shouldn't
  9289. // warn when there is no way of removing the warning.
  9290. /*
  9291. // Warn if the method is non-const and the object is temporary
  9292. // since the changes will be lost when the object is destroyed.
  9293. // If the object is accessed through a handle, then it is assumed
  9294. // the object is not temporary, even though the handle is.
  9295. if( ctx->type.isTemporary &&
  9296. !ctx->type.dataType.IsObjectHandle() &&
  9297. !engine->scriptFunctions[funcId]->isReadOnly )
  9298. {
  9299. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  9300. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  9301. }
  9302. */ }
  9303. asCByteCode objBC(engine);
  9304. objBC.AddCode(&ctx->bc);
  9305. PrepareFunctionCall(funcId, &ctx->bc, args);
  9306. // Verify if any of the args variable offsets are used in the other code.
  9307. // If they are exchange the offset for a new one
  9308. asUINT n;
  9309. for( n = 0; n < args.GetLength(); n++ )
  9310. {
  9311. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  9312. {
  9313. // Release the current temporary variable
  9314. ReleaseTemporaryVariable(args[n]->type, 0);
  9315. asCDataType dt = args[n]->type.dataType;
  9316. dt.MakeReference(false);
  9317. int l = int(reservedVariables.GetLength());
  9318. objBC.GetVarsUsed(reservedVariables);
  9319. ctx->bc.GetVarsUsed(reservedVariables);
  9320. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  9321. reservedVariables.SetLength(l);
  9322. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  9323. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  9324. args[n]->type.stackOffset = (short)newOffset;
  9325. args[n]->type.isTemporary = true;
  9326. args[n]->type.isVariable = true;
  9327. }
  9328. }
  9329. // If the function will return a value type on the stack, then we must allocate space
  9330. // for that here and push the address on the stack as a hidden argument to the function
  9331. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  9332. if( func->DoesReturnOnStack() )
  9333. {
  9334. asASSERT(!useVariable);
  9335. useVariable = true;
  9336. stackOffset = AllocateVariable(func->returnType, true);
  9337. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  9338. }
  9339. ctx->bc.AddCode(&objBC);
  9340. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  9341. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  9342. }
  9343. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9344. {
  9345. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  9346. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  9347. {
  9348. Error(TXT_INVALID_OP_ON_METHOD, node);
  9349. return -1;
  9350. }
  9351. // Don't allow any operators on void expressions
  9352. if( lctx->type.IsVoidExpression() || rctx->type.IsVoidExpression() )
  9353. {
  9354. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9355. return -1;
  9356. }
  9357. IsVariableInitialized(&lctx->type, node);
  9358. IsVariableInitialized(&rctx->type, node);
  9359. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  9360. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  9361. node->tokenType == ttIs || node->tokenType == ttNotIs )
  9362. {
  9363. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  9364. return 0;
  9365. }
  9366. else
  9367. {
  9368. // Compile an overloaded operator for the two operands
  9369. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  9370. return 0;
  9371. // If both operands are objects, then we shouldn't continue
  9372. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  9373. {
  9374. asCString str;
  9375. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  9376. Error(str, node);
  9377. ctx->type.SetDummy();
  9378. return -1;
  9379. }
  9380. // Process the property get accessors (if any)
  9381. ProcessPropertyGetAccessor(lctx, node);
  9382. ProcessPropertyGetAccessor(rctx, node);
  9383. // Make sure we have two variables or constants
  9384. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  9385. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  9386. // Make sure lctx doesn't end up with a variable used in rctx
  9387. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9388. {
  9389. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  9390. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9391. ReleaseTemporaryVariable(offset, 0);
  9392. }
  9393. // Math operators
  9394. // + - * / % += -= *= /= %=
  9395. int op = node->tokenType;
  9396. if( op == ttPlus || op == ttAddAssign ||
  9397. op == ttMinus || op == ttSubAssign ||
  9398. op == ttStar || op == ttMulAssign ||
  9399. op == ttSlash || op == ttDivAssign ||
  9400. op == ttPercent || op == ttModAssign )
  9401. {
  9402. CompileMathOperator(node, lctx, rctx, ctx);
  9403. return 0;
  9404. }
  9405. // Bitwise operators
  9406. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  9407. if( op == ttAmp || op == ttAndAssign ||
  9408. op == ttBitOr || op == ttOrAssign ||
  9409. op == ttBitXor || op == ttXorAssign ||
  9410. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9411. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9412. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9413. {
  9414. CompileBitwiseOperator(node, lctx, rctx, ctx);
  9415. return 0;
  9416. }
  9417. // Comparison operators
  9418. // == != < > <= >=
  9419. if( op == ttEqual || op == ttNotEqual ||
  9420. op == ttLessThan || op == ttLessThanOrEqual ||
  9421. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  9422. {
  9423. CompileComparisonOperator(node, lctx, rctx, ctx);
  9424. return 0;
  9425. }
  9426. // Boolean operators
  9427. // && || ^^
  9428. if( op == ttAnd || op == ttOr || op == ttXor )
  9429. {
  9430. CompileBooleanOperator(node, lctx, rctx, ctx);
  9431. return 0;
  9432. }
  9433. }
  9434. asASSERT(false);
  9435. return -1;
  9436. }
  9437. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9438. {
  9439. int l = int(reservedVariables.GetLength());
  9440. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9441. ConvertToTempVariable(ctx);
  9442. reservedVariables.SetLength(l);
  9443. }
  9444. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  9445. {
  9446. // This is only used for primitive types and null handles
  9447. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  9448. ConvertToVariable(ctx);
  9449. if( !ctx->type.isTemporary )
  9450. {
  9451. if( ctx->type.dataType.IsPrimitive() )
  9452. {
  9453. // Copy the variable to a temporary variable
  9454. int offset = AllocateVariable(ctx->type.dataType, true);
  9455. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9456. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  9457. else
  9458. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  9459. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9460. }
  9461. else
  9462. {
  9463. // We should never get here
  9464. asASSERT(false);
  9465. }
  9466. }
  9467. }
  9468. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  9469. {
  9470. // We should never get here while the context is still an unprocessed property accessor
  9471. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  9472. int offset;
  9473. if( !ctx->type.isVariable &&
  9474. (ctx->type.dataType.IsObjectHandle() ||
  9475. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  9476. {
  9477. offset = AllocateVariable(ctx->type.dataType, true);
  9478. if( ctx->type.IsNullConstant() )
  9479. {
  9480. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  9481. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  9482. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  9483. }
  9484. else
  9485. {
  9486. // Copy the object handle to a variable
  9487. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  9488. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9489. ctx->bc.Instr(asBC_PopPtr);
  9490. }
  9491. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9492. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9493. ctx->type.dataType.MakeHandle(true);
  9494. }
  9495. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  9496. ctx->type.dataType.IsPrimitive() )
  9497. {
  9498. if( ctx->type.isConstant )
  9499. {
  9500. offset = AllocateVariable(ctx->type.dataType, true);
  9501. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9502. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  9503. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9504. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  9505. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9506. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  9507. else
  9508. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  9509. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9510. return;
  9511. }
  9512. else
  9513. {
  9514. asASSERT(ctx->type.dataType.IsPrimitive());
  9515. asASSERT(ctx->type.dataType.IsReference());
  9516. ctx->type.dataType.MakeReference(false);
  9517. offset = AllocateVariable(ctx->type.dataType, true);
  9518. // Read the value from the address in the register directly into the variable
  9519. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9520. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  9521. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9522. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  9523. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9524. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  9525. else
  9526. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  9527. }
  9528. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9529. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9530. }
  9531. }
  9532. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9533. {
  9534. int l = int(reservedVariables.GetLength());
  9535. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9536. ConvertToVariable(ctx);
  9537. reservedVariables.SetLength(l);
  9538. }
  9539. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9540. {
  9541. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9542. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  9543. // Implicitly convert the operands to a number type
  9544. asCDataType to;
  9545. // If either operand is a non-primitive then use the primitive type
  9546. if( !lctx->type.dataType.IsPrimitive() )
  9547. to.SetTokenType(rctx->type.dataType.GetTokenType());
  9548. else if( !rctx->type.dataType.IsPrimitive() )
  9549. to.SetTokenType(lctx->type.dataType.GetTokenType());
  9550. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9551. to.SetTokenType(ttDouble);
  9552. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9553. to.SetTokenType(ttFloat);
  9554. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9555. {
  9556. // Convert to int64 if both are signed or if one is non-constant and signed
  9557. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9558. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9559. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9560. to.SetTokenType(ttInt64);
  9561. else
  9562. to.SetTokenType(ttUInt64);
  9563. }
  9564. else
  9565. {
  9566. // Convert to int32 if both are signed or if one is non-constant and signed
  9567. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9568. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9569. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9570. to.SetTokenType(ttInt);
  9571. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9572. to.SetTokenType(ttUInt);
  9573. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  9574. to.SetTokenType(ttBool);
  9575. }
  9576. // If doing an operation with double constant and float variable, the constant should be converted to float
  9577. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  9578. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  9579. to.SetTokenType(ttFloat);
  9580. // Do the actual conversion
  9581. int l = int(reservedVariables.GetLength());
  9582. rctx->bc.GetVarsUsed(reservedVariables);
  9583. lctx->bc.GetVarsUsed(reservedVariables);
  9584. if( lctx->type.dataType.IsReference() )
  9585. ConvertToVariable(lctx);
  9586. if( rctx->type.dataType.IsReference() )
  9587. ConvertToVariable(rctx);
  9588. if( to.IsPrimitive() )
  9589. {
  9590. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9591. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  9592. }
  9593. reservedVariables.SetLength(l);
  9594. // Verify that the conversion was successful
  9595. if( !lctx->type.dataType.IsIntegerType() &&
  9596. !lctx->type.dataType.IsUnsignedType() &&
  9597. !lctx->type.dataType.IsFloatType() &&
  9598. !lctx->type.dataType.IsDoubleType() )
  9599. {
  9600. asCString str;
  9601. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  9602. Error(str, node);
  9603. ctx->type.SetDummy();
  9604. return;
  9605. }
  9606. if( !rctx->type.dataType.IsIntegerType() &&
  9607. !rctx->type.dataType.IsUnsignedType() &&
  9608. !rctx->type.dataType.IsFloatType() &&
  9609. !rctx->type.dataType.IsDoubleType() )
  9610. {
  9611. asCString str;
  9612. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  9613. Error(str, node);
  9614. ctx->type.SetDummy();
  9615. return;
  9616. }
  9617. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9618. // Verify if we are dividing with a constant zero
  9619. int op = node->tokenType;
  9620. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  9621. (op == ttSlash || op == ttDivAssign ||
  9622. op == ttPercent || op == ttModAssign) )
  9623. {
  9624. Error(TXT_DIVIDE_BY_ZERO, node);
  9625. }
  9626. if( !isConstant )
  9627. {
  9628. ConvertToVariableNotIn(lctx, rctx);
  9629. ConvertToVariableNotIn(rctx, lctx);
  9630. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9631. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9632. if( op == ttAddAssign || op == ttSubAssign ||
  9633. op == ttMulAssign || op == ttDivAssign ||
  9634. op == ttModAssign )
  9635. {
  9636. // Merge the operands in the different order so that they are evaluated correctly
  9637. MergeExprBytecode(ctx, rctx);
  9638. MergeExprBytecode(ctx, lctx);
  9639. // We must not process the deferred parameters yet, as
  9640. // it may overwrite the lvalue kept in the register
  9641. }
  9642. else
  9643. {
  9644. MergeExprBytecode(ctx, lctx);
  9645. MergeExprBytecode(ctx, rctx);
  9646. ProcessDeferredParams(ctx);
  9647. }
  9648. asEBCInstr instruction = asBC_ADDi;
  9649. if( lctx->type.dataType.IsIntegerType() ||
  9650. lctx->type.dataType.IsUnsignedType() )
  9651. {
  9652. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9653. {
  9654. if( op == ttPlus || op == ttAddAssign )
  9655. instruction = asBC_ADDi;
  9656. else if( op == ttMinus || op == ttSubAssign )
  9657. instruction = asBC_SUBi;
  9658. else if( op == ttStar || op == ttMulAssign )
  9659. instruction = asBC_MULi;
  9660. else if( op == ttSlash || op == ttDivAssign )
  9661. {
  9662. if( lctx->type.dataType.IsIntegerType() )
  9663. instruction = asBC_DIVi;
  9664. else
  9665. instruction = asBC_DIVu;
  9666. }
  9667. else if( op == ttPercent || op == ttModAssign )
  9668. {
  9669. if( lctx->type.dataType.IsIntegerType() )
  9670. instruction = asBC_MODi;
  9671. else
  9672. instruction = asBC_MODu;
  9673. }
  9674. }
  9675. else
  9676. {
  9677. if( op == ttPlus || op == ttAddAssign )
  9678. instruction = asBC_ADDi64;
  9679. else if( op == ttMinus || op == ttSubAssign )
  9680. instruction = asBC_SUBi64;
  9681. else if( op == ttStar || op == ttMulAssign )
  9682. instruction = asBC_MULi64;
  9683. else if( op == ttSlash || op == ttDivAssign )
  9684. {
  9685. if( lctx->type.dataType.IsIntegerType() )
  9686. instruction = asBC_DIVi64;
  9687. else
  9688. instruction = asBC_DIVu64;
  9689. }
  9690. else if( op == ttPercent || op == ttModAssign )
  9691. {
  9692. if( lctx->type.dataType.IsIntegerType() )
  9693. instruction = asBC_MODi64;
  9694. else
  9695. instruction = asBC_MODu64;
  9696. }
  9697. }
  9698. }
  9699. else if( lctx->type.dataType.IsFloatType() )
  9700. {
  9701. if( op == ttPlus || op == ttAddAssign )
  9702. instruction = asBC_ADDf;
  9703. else if( op == ttMinus || op == ttSubAssign )
  9704. instruction = asBC_SUBf;
  9705. else if( op == ttStar || op == ttMulAssign )
  9706. instruction = asBC_MULf;
  9707. else if( op == ttSlash || op == ttDivAssign )
  9708. instruction = asBC_DIVf;
  9709. else if( op == ttPercent || op == ttModAssign )
  9710. instruction = asBC_MODf;
  9711. }
  9712. else if( lctx->type.dataType.IsDoubleType() )
  9713. {
  9714. if( op == ttPlus || op == ttAddAssign )
  9715. instruction = asBC_ADDd;
  9716. else if( op == ttMinus || op == ttSubAssign )
  9717. instruction = asBC_SUBd;
  9718. else if( op == ttStar || op == ttMulAssign )
  9719. instruction = asBC_MULd;
  9720. else if( op == ttSlash || op == ttDivAssign )
  9721. instruction = asBC_DIVd;
  9722. else if( op == ttPercent || op == ttModAssign )
  9723. instruction = asBC_MODd;
  9724. }
  9725. else
  9726. {
  9727. // Shouldn't be possible
  9728. asASSERT(false);
  9729. }
  9730. // Do the operation
  9731. int a = AllocateVariable(lctx->type.dataType, true);
  9732. int b = lctx->type.stackOffset;
  9733. int c = rctx->type.stackOffset;
  9734. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9735. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9736. }
  9737. else
  9738. {
  9739. // Both values are constants
  9740. if( lctx->type.dataType.IsIntegerType() ||
  9741. lctx->type.dataType.IsUnsignedType() )
  9742. {
  9743. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9744. {
  9745. int v = 0;
  9746. if( op == ttPlus )
  9747. v = lctx->type.intValue + rctx->type.intValue;
  9748. else if( op == ttMinus )
  9749. v = lctx->type.intValue - rctx->type.intValue;
  9750. else if( op == ttStar )
  9751. v = lctx->type.intValue * rctx->type.intValue;
  9752. else if( op == ttSlash )
  9753. {
  9754. // TODO: Should probably report an error, rather than silently convert the value to 0
  9755. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9756. v = 0;
  9757. else
  9758. if( lctx->type.dataType.IsIntegerType() )
  9759. v = lctx->type.intValue / rctx->type.intValue;
  9760. else
  9761. v = lctx->type.dwordValue / rctx->type.dwordValue;
  9762. }
  9763. else if( op == ttPercent )
  9764. {
  9765. // TODO: Should probably report an error, rather than silently convert the value to 0
  9766. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9767. v = 0;
  9768. else
  9769. if( lctx->type.dataType.IsIntegerType() )
  9770. v = lctx->type.intValue % rctx->type.intValue;
  9771. else
  9772. v = lctx->type.dwordValue % rctx->type.dwordValue;
  9773. }
  9774. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9775. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9776. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  9777. ctx->type.dataType.SetTokenType(ttInt);
  9778. }
  9779. else
  9780. {
  9781. asQWORD v = 0;
  9782. if( op == ttPlus )
  9783. v = lctx->type.qwordValue + rctx->type.qwordValue;
  9784. else if( op == ttMinus )
  9785. v = lctx->type.qwordValue - rctx->type.qwordValue;
  9786. else if( op == ttStar )
  9787. v = lctx->type.qwordValue * rctx->type.qwordValue;
  9788. else if( op == ttSlash )
  9789. {
  9790. // TODO: Should probably report an error, rather than silently convert the value to 0
  9791. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9792. v = 0;
  9793. else
  9794. if( lctx->type.dataType.IsIntegerType() )
  9795. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  9796. else
  9797. v = lctx->type.qwordValue / rctx->type.qwordValue;
  9798. }
  9799. else if( op == ttPercent )
  9800. {
  9801. // TODO: Should probably report an error, rather than silently convert the value to 0
  9802. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9803. v = 0;
  9804. else
  9805. if( lctx->type.dataType.IsIntegerType() )
  9806. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  9807. else
  9808. v = lctx->type.qwordValue % rctx->type.qwordValue;
  9809. }
  9810. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9811. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9812. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  9813. ctx->type.dataType.SetTokenType(ttInt64);
  9814. }
  9815. }
  9816. else if( lctx->type.dataType.IsFloatType() )
  9817. {
  9818. float v = 0.0f;
  9819. if( op == ttPlus )
  9820. v = lctx->type.floatValue + rctx->type.floatValue;
  9821. else if( op == ttMinus )
  9822. v = lctx->type.floatValue - rctx->type.floatValue;
  9823. else if( op == ttStar )
  9824. v = lctx->type.floatValue * rctx->type.floatValue;
  9825. else if( op == ttSlash )
  9826. {
  9827. if( rctx->type.floatValue == 0 )
  9828. v = 0;
  9829. else
  9830. v = lctx->type.floatValue / rctx->type.floatValue;
  9831. }
  9832. else if( op == ttPercent )
  9833. {
  9834. if( rctx->type.floatValue == 0 )
  9835. v = 0;
  9836. else
  9837. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  9838. }
  9839. ctx->type.SetConstantF(lctx->type.dataType, v);
  9840. }
  9841. else if( lctx->type.dataType.IsDoubleType() )
  9842. {
  9843. double v = 0.0;
  9844. if( op == ttPlus )
  9845. v = lctx->type.doubleValue + rctx->type.doubleValue;
  9846. else if( op == ttMinus )
  9847. v = lctx->type.doubleValue - rctx->type.doubleValue;
  9848. else if( op == ttStar )
  9849. v = lctx->type.doubleValue * rctx->type.doubleValue;
  9850. else if( op == ttSlash )
  9851. {
  9852. if( rctx->type.doubleValue == 0 )
  9853. v = 0;
  9854. else
  9855. v = lctx->type.doubleValue / rctx->type.doubleValue;
  9856. }
  9857. else if( op == ttPercent )
  9858. {
  9859. if( rctx->type.doubleValue == 0 )
  9860. v = 0;
  9861. else
  9862. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  9863. }
  9864. ctx->type.SetConstantD(lctx->type.dataType, v);
  9865. }
  9866. else
  9867. {
  9868. // Shouldn't be possible
  9869. asASSERT(false);
  9870. }
  9871. }
  9872. }
  9873. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9874. {
  9875. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9876. int op = node->tokenType;
  9877. if( op == ttAmp || op == ttAndAssign ||
  9878. op == ttBitOr || op == ttOrAssign ||
  9879. op == ttBitXor || op == ttXorAssign )
  9880. {
  9881. // Convert left hand operand to integer if it's not already one
  9882. asCDataType to;
  9883. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  9884. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9885. to.SetTokenType(ttUInt64);
  9886. else
  9887. to.SetTokenType(ttUInt);
  9888. // Do the actual conversion
  9889. int l = int(reservedVariables.GetLength());
  9890. rctx->bc.GetVarsUsed(reservedVariables);
  9891. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9892. reservedVariables.SetLength(l);
  9893. // Verify that the conversion was successful
  9894. if( !lctx->type.dataType.IsUnsignedType() )
  9895. {
  9896. asCString str;
  9897. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9898. Error(str, node);
  9899. }
  9900. // Convert right hand operand to same type as left hand operand
  9901. l = int(reservedVariables.GetLength());
  9902. lctx->bc.GetVarsUsed(reservedVariables);
  9903. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true);
  9904. reservedVariables.SetLength(l);
  9905. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  9906. {
  9907. asCString str;
  9908. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  9909. Error(str, node);
  9910. }
  9911. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9912. if( !isConstant )
  9913. {
  9914. ConvertToVariableNotIn(lctx, rctx);
  9915. ConvertToVariableNotIn(rctx, lctx);
  9916. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9917. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9918. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  9919. {
  9920. // Compound assignments execute the right hand value first
  9921. MergeExprBytecode(ctx, rctx);
  9922. MergeExprBytecode(ctx, lctx);
  9923. }
  9924. else
  9925. {
  9926. MergeExprBytecode(ctx, lctx);
  9927. MergeExprBytecode(ctx, rctx);
  9928. }
  9929. ProcessDeferredParams(ctx);
  9930. asEBCInstr instruction = asBC_BAND;
  9931. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9932. {
  9933. if( op == ttAmp || op == ttAndAssign )
  9934. instruction = asBC_BAND;
  9935. else if( op == ttBitOr || op == ttOrAssign )
  9936. instruction = asBC_BOR;
  9937. else if( op == ttBitXor || op == ttXorAssign )
  9938. instruction = asBC_BXOR;
  9939. }
  9940. else
  9941. {
  9942. if( op == ttAmp || op == ttAndAssign )
  9943. instruction = asBC_BAND64;
  9944. else if( op == ttBitOr || op == ttOrAssign )
  9945. instruction = asBC_BOR64;
  9946. else if( op == ttBitXor || op == ttXorAssign )
  9947. instruction = asBC_BXOR64;
  9948. }
  9949. // Do the operation
  9950. int a = AllocateVariable(lctx->type.dataType, true);
  9951. int b = lctx->type.stackOffset;
  9952. int c = rctx->type.stackOffset;
  9953. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9954. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9955. }
  9956. else
  9957. {
  9958. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9959. {
  9960. asQWORD v = 0;
  9961. if( op == ttAmp )
  9962. v = lctx->type.qwordValue & rctx->type.qwordValue;
  9963. else if( op == ttBitOr )
  9964. v = lctx->type.qwordValue | rctx->type.qwordValue;
  9965. else if( op == ttBitXor )
  9966. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  9967. // Remember the result
  9968. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9969. }
  9970. else
  9971. {
  9972. asDWORD v = 0;
  9973. if( op == ttAmp )
  9974. v = lctx->type.dwordValue & rctx->type.dwordValue;
  9975. else if( op == ttBitOr )
  9976. v = lctx->type.dwordValue | rctx->type.dwordValue;
  9977. else if( op == ttBitXor )
  9978. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  9979. // Remember the result
  9980. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9981. }
  9982. }
  9983. }
  9984. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9985. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9986. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9987. {
  9988. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  9989. if( lctx->type.dataType.IsObject() )
  9990. {
  9991. asCString str;
  9992. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  9993. Error(str, node);
  9994. // Set an integer value and allow the compiler to continue
  9995. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  9996. return;
  9997. }
  9998. // Convert left hand operand to integer if it's not already one
  9999. asCDataType to = lctx->type.dataType;
  10000. if( lctx->type.dataType.IsUnsignedType() &&
  10001. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  10002. {
  10003. to = asCDataType::CreatePrimitive(ttUInt, false);
  10004. }
  10005. else if( !lctx->type.dataType.IsUnsignedType() )
  10006. {
  10007. asCDataType to;
  10008. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10009. to.SetTokenType(ttInt64);
  10010. else
  10011. to.SetTokenType(ttInt);
  10012. }
  10013. // Do the actual conversion
  10014. int l = int(reservedVariables.GetLength());
  10015. rctx->bc.GetVarsUsed(reservedVariables);
  10016. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  10017. reservedVariables.SetLength(l);
  10018. // Verify that the conversion was successful
  10019. if( lctx->type.dataType != to )
  10020. {
  10021. asCString str;
  10022. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10023. Error(str, node);
  10024. }
  10025. // Right operand must be 32bit uint
  10026. l = int(reservedVariables.GetLength());
  10027. lctx->bc.GetVarsUsed(reservedVariables);
  10028. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  10029. reservedVariables.SetLength(l);
  10030. if( !rctx->type.dataType.IsUnsignedType() )
  10031. {
  10032. asCString str;
  10033. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  10034. Error(str, node);
  10035. }
  10036. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10037. if( !isConstant )
  10038. {
  10039. ConvertToVariableNotIn(lctx, rctx);
  10040. ConvertToVariableNotIn(rctx, lctx);
  10041. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10042. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10043. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  10044. {
  10045. // Compound assignments execute the right hand value first
  10046. MergeExprBytecode(ctx, rctx);
  10047. MergeExprBytecode(ctx, lctx);
  10048. }
  10049. else
  10050. {
  10051. MergeExprBytecode(ctx, lctx);
  10052. MergeExprBytecode(ctx, rctx);
  10053. }
  10054. ProcessDeferredParams(ctx);
  10055. asEBCInstr instruction = asBC_BSLL;
  10056. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10057. {
  10058. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  10059. instruction = asBC_BSLL;
  10060. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  10061. instruction = asBC_BSRL;
  10062. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10063. instruction = asBC_BSRA;
  10064. }
  10065. else
  10066. {
  10067. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  10068. instruction = asBC_BSLL64;
  10069. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  10070. instruction = asBC_BSRL64;
  10071. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  10072. instruction = asBC_BSRA64;
  10073. }
  10074. // Do the operation
  10075. int a = AllocateVariable(lctx->type.dataType, true);
  10076. int b = lctx->type.stackOffset;
  10077. int c = rctx->type.stackOffset;
  10078. ctx->bc.InstrW_W_W(instruction, a, b, c);
  10079. ctx->type.SetVariable(lctx->type.dataType, a, true);
  10080. }
  10081. else
  10082. {
  10083. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10084. {
  10085. asDWORD v = 0;
  10086. if( op == ttBitShiftLeft )
  10087. v = lctx->type.dwordValue << rctx->type.dwordValue;
  10088. else if( op == ttBitShiftRight )
  10089. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  10090. else if( op == ttBitShiftRightArith )
  10091. v = lctx->type.intValue >> rctx->type.dwordValue;
  10092. ctx->type.SetConstantDW(lctx->type.dataType, v);
  10093. }
  10094. else
  10095. {
  10096. asQWORD v = 0;
  10097. if( op == ttBitShiftLeft )
  10098. v = lctx->type.qwordValue << rctx->type.dwordValue;
  10099. else if( op == ttBitShiftRight )
  10100. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  10101. else if( op == ttBitShiftRightArith )
  10102. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  10103. ctx->type.SetConstantQW(lctx->type.dataType, v);
  10104. }
  10105. }
  10106. }
  10107. }
  10108. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10109. {
  10110. // Both operands must be of the same type
  10111. // Implicitly convert the operands to a number type
  10112. asCDataType to;
  10113. // If either operand is a non-primitive then use the primitive type
  10114. if( !lctx->type.dataType.IsPrimitive() )
  10115. to.SetTokenType(rctx->type.dataType.GetTokenType());
  10116. else if( !rctx->type.dataType.IsPrimitive() )
  10117. to.SetTokenType(lctx->type.dataType.GetTokenType());
  10118. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  10119. to.SetTokenType(ttDouble);
  10120. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  10121. to.SetTokenType(ttFloat);
  10122. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10123. {
  10124. // Convert to int64 if both are signed or if one is non-constant and signed
  10125. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  10126. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10127. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10128. to.SetTokenType(ttInt64);
  10129. else
  10130. to.SetTokenType(ttUInt64);
  10131. }
  10132. else
  10133. {
  10134. // Convert to int32 if both are signed or if one is non-constant and signed
  10135. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  10136. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10137. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10138. to.SetTokenType(ttInt);
  10139. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10140. to.SetTokenType(ttUInt);
  10141. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  10142. to.SetTokenType(ttBool);
  10143. }
  10144. // If doing an operation with double constant and float variable, the constant should be converted to float
  10145. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  10146. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  10147. to.SetTokenType(ttFloat);
  10148. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  10149. // Do we have a mismatch between the sign of the operand?
  10150. bool signMismatch = false;
  10151. for( int n = 0; !signMismatch && n < 2; n++ )
  10152. {
  10153. asSExprContext *op = n ? rctx : lctx;
  10154. if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  10155. {
  10156. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  10157. signMismatch = true;
  10158. if( op->type.isConstant )
  10159. {
  10160. if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
  10161. {
  10162. if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
  10163. signMismatch = false;
  10164. }
  10165. else
  10166. {
  10167. if( !(op->type.dwordValue & (1<<31)) )
  10168. signMismatch = false;
  10169. }
  10170. // It's not necessary to check for floats or double, because if
  10171. // it was then the types for the conversion will never be unsigned
  10172. }
  10173. }
  10174. }
  10175. // Check for signed/unsigned mismatch
  10176. if( signMismatch )
  10177. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  10178. // Do the actual conversion
  10179. int l = int(reservedVariables.GetLength());
  10180. rctx->bc.GetVarsUsed(reservedVariables);
  10181. if( lctx->type.dataType.IsReference() )
  10182. ConvertToVariable(lctx);
  10183. if( rctx->type.dataType.IsReference() )
  10184. ConvertToVariable(rctx);
  10185. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10186. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10187. reservedVariables.SetLength(l);
  10188. // Verify that the conversion was successful
  10189. bool ok = true;
  10190. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  10191. {
  10192. asCString str;
  10193. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10194. Error(str, node);
  10195. ok = false;
  10196. }
  10197. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  10198. {
  10199. asCString str;
  10200. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10201. Error(str, node);
  10202. ok = false;
  10203. }
  10204. if( !ok )
  10205. {
  10206. // It wasn't possible to get two valid operands, so we just return
  10207. // a boolean result and let the compiler continue.
  10208. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10209. return;
  10210. }
  10211. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10212. int op = node->tokenType;
  10213. if( !isConstant )
  10214. {
  10215. if( to.IsBooleanType() )
  10216. {
  10217. int op = node->tokenType;
  10218. if( op == ttEqual || op == ttNotEqual )
  10219. {
  10220. // Must convert to temporary variable, because we are changing the value before comparison
  10221. ConvertToTempVariableNotIn(lctx, rctx);
  10222. ConvertToTempVariableNotIn(rctx, lctx);
  10223. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10224. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10225. // Make sure they are equal if not false
  10226. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  10227. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  10228. MergeExprBytecode(ctx, lctx);
  10229. MergeExprBytecode(ctx, rctx);
  10230. ProcessDeferredParams(ctx);
  10231. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  10232. int b = lctx->type.stackOffset;
  10233. int c = rctx->type.stackOffset;
  10234. if( op == ttEqual )
  10235. {
  10236. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  10237. ctx->bc.Instr(asBC_TZ);
  10238. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10239. }
  10240. else if( op == ttNotEqual )
  10241. {
  10242. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  10243. ctx->bc.Instr(asBC_TNZ);
  10244. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10245. }
  10246. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10247. }
  10248. else
  10249. {
  10250. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10251. Error(TXT_ILLEGAL_OPERATION, node);
  10252. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  10253. }
  10254. }
  10255. else
  10256. {
  10257. ConvertToVariableNotIn(lctx, rctx);
  10258. ConvertToVariableNotIn(rctx, lctx);
  10259. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10260. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10261. MergeExprBytecode(ctx, lctx);
  10262. MergeExprBytecode(ctx, rctx);
  10263. ProcessDeferredParams(ctx);
  10264. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  10265. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10266. iCmp = asBC_CMPi;
  10267. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10268. iCmp = asBC_CMPu;
  10269. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10270. iCmp = asBC_CMPi64;
  10271. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10272. iCmp = asBC_CMPu64;
  10273. else if( lctx->type.dataType.IsFloatType() )
  10274. iCmp = asBC_CMPf;
  10275. else if( lctx->type.dataType.IsDoubleType() )
  10276. iCmp = asBC_CMPd;
  10277. else
  10278. asASSERT(false);
  10279. if( op == ttEqual )
  10280. iT = asBC_TZ;
  10281. else if( op == ttNotEqual )
  10282. iT = asBC_TNZ;
  10283. else if( op == ttLessThan )
  10284. iT = asBC_TS;
  10285. else if( op == ttLessThanOrEqual )
  10286. iT = asBC_TNP;
  10287. else if( op == ttGreaterThan )
  10288. iT = asBC_TP;
  10289. else if( op == ttGreaterThanOrEqual )
  10290. iT = asBC_TNS;
  10291. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  10292. int b = lctx->type.stackOffset;
  10293. int c = rctx->type.stackOffset;
  10294. ctx->bc.InstrW_W(iCmp, b, c);
  10295. ctx->bc.Instr(iT);
  10296. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10297. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10298. }
  10299. }
  10300. else
  10301. {
  10302. if( to.IsBooleanType() )
  10303. {
  10304. int op = node->tokenType;
  10305. if( op == ttEqual || op == ttNotEqual )
  10306. {
  10307. // Make sure they are equal if not false
  10308. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10309. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10310. asDWORD v = 0;
  10311. if( op == ttEqual )
  10312. {
  10313. v = lctx->type.intValue - rctx->type.intValue;
  10314. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10315. }
  10316. else if( op == ttNotEqual )
  10317. {
  10318. v = lctx->type.intValue - rctx->type.intValue;
  10319. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10320. }
  10321. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  10322. }
  10323. else
  10324. {
  10325. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10326. Error(TXT_ILLEGAL_OPERATION, node);
  10327. }
  10328. }
  10329. else
  10330. {
  10331. int i = 0;
  10332. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10333. {
  10334. int v = lctx->type.intValue - rctx->type.intValue;
  10335. if( v < 0 ) i = -1;
  10336. if( v > 0 ) i = 1;
  10337. }
  10338. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10339. {
  10340. asDWORD v1 = lctx->type.dwordValue;
  10341. asDWORD v2 = rctx->type.dwordValue;
  10342. if( v1 < v2 ) i = -1;
  10343. if( v1 > v2 ) i = 1;
  10344. }
  10345. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10346. {
  10347. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  10348. if( v < 0 ) i = -1;
  10349. if( v > 0 ) i = 1;
  10350. }
  10351. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10352. {
  10353. asQWORD v1 = lctx->type.qwordValue;
  10354. asQWORD v2 = rctx->type.qwordValue;
  10355. if( v1 < v2 ) i = -1;
  10356. if( v1 > v2 ) i = 1;
  10357. }
  10358. else if( lctx->type.dataType.IsFloatType() )
  10359. {
  10360. float v = lctx->type.floatValue - rctx->type.floatValue;
  10361. if( v < 0 ) i = -1;
  10362. if( v > 0 ) i = 1;
  10363. }
  10364. else if( lctx->type.dataType.IsDoubleType() )
  10365. {
  10366. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  10367. if( v < 0 ) i = -1;
  10368. if( v > 0 ) i = 1;
  10369. }
  10370. if( op == ttEqual )
  10371. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10372. else if( op == ttNotEqual )
  10373. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10374. else if( op == ttLessThan )
  10375. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10376. else if( op == ttLessThanOrEqual )
  10377. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10378. else if( op == ttGreaterThan )
  10379. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10380. else if( op == ttGreaterThanOrEqual )
  10381. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10382. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  10383. }
  10384. }
  10385. }
  10386. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  10387. {
  10388. // Put the result on the stack
  10389. if( asReference )
  10390. {
  10391. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  10392. ctx->type.dataType.MakeReference(true);
  10393. }
  10394. else
  10395. {
  10396. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10397. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  10398. else
  10399. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  10400. }
  10401. }
  10402. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10403. {
  10404. // Both operands must be booleans
  10405. asCDataType to;
  10406. to.SetTokenType(ttBool);
  10407. // Do the actual conversion
  10408. int l = int(reservedVariables.GetLength());
  10409. rctx->bc.GetVarsUsed(reservedVariables);
  10410. lctx->bc.GetVarsUsed(reservedVariables);
  10411. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10412. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10413. reservedVariables.SetLength(l);
  10414. // Verify that the conversion was successful
  10415. if( !lctx->type.dataType.IsBooleanType() )
  10416. {
  10417. asCString str;
  10418. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  10419. Error(str, node);
  10420. // Force the conversion to allow compilation to proceed
  10421. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10422. }
  10423. if( !rctx->type.dataType.IsBooleanType() )
  10424. {
  10425. asCString str;
  10426. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  10427. Error(str, node);
  10428. // Force the conversion to allow compilation to proceed
  10429. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10430. }
  10431. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10432. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10433. // What kind of operator is it?
  10434. int op = node->tokenType;
  10435. if( op == ttXor )
  10436. {
  10437. if( !isConstant )
  10438. {
  10439. // Must convert to temporary variable, because we are changing the value before comparison
  10440. ConvertToTempVariableNotIn(lctx, rctx);
  10441. ConvertToTempVariableNotIn(rctx, lctx);
  10442. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10443. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10444. // Make sure they are equal if not false
  10445. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  10446. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  10447. MergeExprBytecode(ctx, lctx);
  10448. MergeExprBytecode(ctx, rctx);
  10449. ProcessDeferredParams(ctx);
  10450. int a = AllocateVariable(ctx->type.dataType, true);
  10451. int b = lctx->type.stackOffset;
  10452. int c = rctx->type.stackOffset;
  10453. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  10454. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10455. }
  10456. else
  10457. {
  10458. // Make sure they are equal if not false
  10459. #if AS_SIZEOF_BOOL == 1
  10460. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10461. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10462. asBYTE v = 0;
  10463. v = lctx->type.byteValue - rctx->type.byteValue;
  10464. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10465. ctx->type.isConstant = true;
  10466. ctx->type.byteValue = v;
  10467. #else
  10468. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10469. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10470. asDWORD v = 0;
  10471. v = lctx->type.intValue - rctx->type.intValue;
  10472. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10473. ctx->type.isConstant = true;
  10474. ctx->type.dwordValue = v;
  10475. #endif
  10476. }
  10477. }
  10478. else if( op == ttAnd ||
  10479. op == ttOr )
  10480. {
  10481. if( !isConstant )
  10482. {
  10483. // If or-operator and first value is 1 the second value shouldn't be calculated
  10484. // if and-operator and first value is 0 the second value shouldn't be calculated
  10485. ConvertToVariable(lctx);
  10486. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10487. MergeExprBytecode(ctx, lctx);
  10488. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  10489. int label1 = nextLabel++;
  10490. int label2 = nextLabel++;
  10491. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  10492. ctx->bc.Instr(asBC_ClrHi);
  10493. if( op == ttAnd )
  10494. {
  10495. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  10496. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  10497. ctx->bc.InstrINT(asBC_JMP, label2);
  10498. }
  10499. else if( op == ttOr )
  10500. {
  10501. ctx->bc.InstrDWORD(asBC_JZ, label1);
  10502. #if AS_SIZEOF_BOOL == 1
  10503. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10504. #else
  10505. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10506. #endif
  10507. ctx->bc.InstrINT(asBC_JMP, label2);
  10508. }
  10509. ctx->bc.Label((short)label1);
  10510. ConvertToVariable(rctx);
  10511. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10512. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  10513. MergeExprBytecode(ctx, rctx);
  10514. ctx->bc.Label((short)label2);
  10515. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  10516. }
  10517. else
  10518. {
  10519. #if AS_SIZEOF_BOOL == 1
  10520. asBYTE v = 0;
  10521. if( op == ttAnd )
  10522. v = lctx->type.byteValue && rctx->type.byteValue;
  10523. else if( op == ttOr )
  10524. v = lctx->type.byteValue || rctx->type.byteValue;
  10525. // Remember the result
  10526. ctx->type.isConstant = true;
  10527. ctx->type.byteValue = v;
  10528. #else
  10529. asDWORD v = 0;
  10530. if( op == ttAnd )
  10531. v = lctx->type.dwordValue && rctx->type.dwordValue;
  10532. else if( op == ttOr )
  10533. v = lctx->type.dwordValue || rctx->type.dwordValue;
  10534. // Remember the result
  10535. ctx->type.isConstant = true;
  10536. ctx->type.dwordValue = v;
  10537. #endif
  10538. }
  10539. }
  10540. }
  10541. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10542. {
  10543. // Process the property accessor as get
  10544. ProcessPropertyGetAccessor(lctx, node);
  10545. ProcessPropertyGetAccessor(rctx, node);
  10546. DetermineSingleFunc(lctx, node);
  10547. DetermineSingleFunc(rctx, node);
  10548. // Make sure lctx doesn't end up with a variable used in rctx
  10549. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10550. {
  10551. asCArray<int> vars;
  10552. rctx->bc.GetVarsUsed(vars);
  10553. int offset = AllocateVariable(lctx->type.dataType, true);
  10554. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  10555. ReleaseTemporaryVariable(offset, 0);
  10556. }
  10557. // Warn if not both operands are explicit handles or null handles
  10558. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  10559. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  10560. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  10561. {
  10562. Warning(TXT_HANDLE_COMPARISON, node);
  10563. }
  10564. // If one of the operands is a value type used as handle, we should look for the opEquals method
  10565. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  10566. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  10567. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  10568. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  10569. {
  10570. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10571. // Find the matching opEquals method
  10572. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10573. if( r == 0 )
  10574. {
  10575. // Try again by switching the order of the operands
  10576. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10577. }
  10578. if( r == 1 )
  10579. {
  10580. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  10581. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10582. // Success, don't continue
  10583. return;
  10584. }
  10585. else if( r == 0 )
  10586. {
  10587. // Couldn't find opEquals method
  10588. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  10589. }
  10590. // Compiler error, don't continue
  10591. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10592. return;
  10593. }
  10594. // Implicitly convert null to the other type
  10595. asCDataType to;
  10596. if( lctx->type.IsNullConstant() )
  10597. to = rctx->type.dataType;
  10598. else if( rctx->type.IsNullConstant() )
  10599. to = lctx->type.dataType;
  10600. else
  10601. {
  10602. // TODO: Use the common base type
  10603. to = lctx->type.dataType;
  10604. }
  10605. // Need to pop the value if it is a null constant
  10606. if( lctx->type.IsNullConstant() )
  10607. lctx->bc.Instr(asBC_PopPtr);
  10608. if( rctx->type.IsNullConstant() )
  10609. rctx->bc.Instr(asBC_PopPtr);
  10610. // Convert both sides to explicit handles
  10611. to.MakeHandle(true);
  10612. to.MakeReference(false);
  10613. if( !to.IsObjectHandle() )
  10614. {
  10615. // Compiler error, don't continue
  10616. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10617. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10618. return;
  10619. }
  10620. // Do the conversion
  10621. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10622. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10623. // Both operands must be of the same type
  10624. // Verify that the conversion was successful
  10625. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  10626. {
  10627. asCString str;
  10628. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10629. Error(str, node);
  10630. }
  10631. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  10632. {
  10633. asCString str;
  10634. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10635. Error(str, node);
  10636. }
  10637. // Make sure it really is handles that are being compared
  10638. if( !lctx->type.dataType.IsObjectHandle() )
  10639. {
  10640. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10641. }
  10642. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10643. int op = node->tokenType;
  10644. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  10645. {
  10646. // If the object handle already is in a variable we must manually pop it from the stack
  10647. if( lctx->type.isVariable )
  10648. lctx->bc.Instr(asBC_PopPtr);
  10649. if( rctx->type.isVariable )
  10650. rctx->bc.Instr(asBC_PopPtr);
  10651. // TODO: runtime optimize: don't do REFCPY
  10652. ConvertToVariableNotIn(lctx, rctx);
  10653. ConvertToVariable(rctx);
  10654. MergeExprBytecode(ctx, lctx);
  10655. MergeExprBytecode(ctx, rctx);
  10656. int a = AllocateVariable(ctx->type.dataType, true);
  10657. int b = lctx->type.stackOffset;
  10658. int c = rctx->type.stackOffset;
  10659. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  10660. if( op == ttEqual || op == ttIs )
  10661. ctx->bc.Instr(asBC_TZ);
  10662. else if( op == ttNotEqual || op == ttNotIs )
  10663. ctx->bc.Instr(asBC_TNZ);
  10664. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10665. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10666. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  10667. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  10668. ProcessDeferredParams(ctx);
  10669. }
  10670. else
  10671. {
  10672. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10673. Error(TXT_ILLEGAL_OPERATION, node);
  10674. }
  10675. }
  10676. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  10677. {
  10678. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  10679. // A shared object may not call non-shared functions
  10680. if( outFunc->IsShared() && !descr->IsShared() )
  10681. {
  10682. asCString msg;
  10683. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  10684. Error(msg, ctx->exprNode);
  10685. }
  10686. // Check if the function is private
  10687. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  10688. {
  10689. asCString msg;
  10690. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  10691. Error(msg, ctx->exprNode);
  10692. }
  10693. int argSize = descr->GetSpaceNeededForArguments();
  10694. if( descr->objectType && descr->returnType.IsReference() &&
  10695. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  10696. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  10697. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  10698. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  10699. {
  10700. // The class method we're calling is returning a reference, which may be to a member of the object.
  10701. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  10702. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  10703. int tempRef = AllocateVariable(ctx->type.dataType, true);
  10704. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  10705. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  10706. // Add the release of this reference, as a deferred expression
  10707. asSDeferredParam deferred;
  10708. deferred.origExpr = 0;
  10709. deferred.argInOutFlags = asTM_INREF;
  10710. deferred.argNode = 0;
  10711. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  10712. ctx->deferredParams.PushLast(deferred);
  10713. // Forget the current type
  10714. ctx->type.SetDummy();
  10715. }
  10716. if( isConstructor )
  10717. {
  10718. // Sometimes the value types are allocated on the heap,
  10719. // which is when this way of constructing them is used.
  10720. asASSERT(useVariable == false);
  10721. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  10722. // The instruction has already moved the returned object to the variable
  10723. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  10724. ctx->type.isLValue = false;
  10725. // Clean up arguments
  10726. if( args )
  10727. AfterFunctionCall(funcId, *args, ctx, false);
  10728. ProcessDeferredParams(ctx);
  10729. return;
  10730. }
  10731. else
  10732. {
  10733. if( descr->objectType )
  10734. argSize += AS_PTR_SIZE;
  10735. // If the function returns an object by value the address of the location
  10736. // where the value should be stored is passed as an argument too
  10737. if( descr->DoesReturnOnStack() )
  10738. {
  10739. argSize += AS_PTR_SIZE;
  10740. }
  10741. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  10742. // should be made with asBC_CALL as it is faster. Examples where this
  10743. // is known is for example finalled methods where the class doesn't derive
  10744. // from any other, or even non-finalled methods but where it is known
  10745. // at compile time the true type of the object. The first should be
  10746. // quite easy to determine, but the latter will be quite complex and possibly
  10747. // not worth it.
  10748. if( descr->funcType == asFUNC_IMPORTED )
  10749. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  10750. // TODO: Maybe we need two different byte codes
  10751. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  10752. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  10753. else if( descr->funcType == asFUNC_SCRIPT )
  10754. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  10755. else if( descr->funcType == asFUNC_SYSTEM )
  10756. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  10757. else if( descr->funcType == asFUNC_FUNCDEF )
  10758. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  10759. }
  10760. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  10761. {
  10762. int returnOffset = 0;
  10763. if( descr->DoesReturnOnStack() )
  10764. {
  10765. asASSERT( useVariable );
  10766. // The variable was allocated before the function was called
  10767. returnOffset = varOffset;
  10768. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10769. // The variable was initialized by the function, so we need to mark it as initialized here
  10770. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  10771. }
  10772. else
  10773. {
  10774. if( useVariable )
  10775. {
  10776. // Use the given variable
  10777. returnOffset = varOffset;
  10778. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  10779. }
  10780. else
  10781. {
  10782. // Allocate a temporary variable for the returned object
  10783. // The returned object will actually be allocated on the heap, so
  10784. // we must force the allocation of the variable to do the same
  10785. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  10786. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10787. }
  10788. // Move the pointer from the object register to the temporary variable
  10789. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  10790. }
  10791. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  10792. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  10793. // Clean up arguments
  10794. if( args )
  10795. AfterFunctionCall(funcId, *args, ctx, false);
  10796. ProcessDeferredParams(ctx);
  10797. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  10798. }
  10799. else if( descr->returnType.IsReference() )
  10800. {
  10801. asASSERT(useVariable == false);
  10802. // We cannot clean up the arguments yet, because the
  10803. // reference might be pointing to one of them.
  10804. if( args )
  10805. AfterFunctionCall(funcId, *args, ctx, true);
  10806. // Do not process the output parameters yet, because it
  10807. // might invalidate the returned reference
  10808. // If the context holds a variable that needs cleanup
  10809. // store it as a deferred parameter so it will be cleaned up
  10810. // afterwards.
  10811. if( ctx->type.isTemporary )
  10812. {
  10813. asSDeferredParam defer;
  10814. defer.argNode = 0;
  10815. defer.argType = ctx->type;
  10816. defer.argInOutFlags = asTM_INOUTREF;
  10817. defer.origExpr = 0;
  10818. ctx->deferredParams.PushLast(defer);
  10819. }
  10820. ctx->type.Set(descr->returnType);
  10821. if( !descr->returnType.IsPrimitive() )
  10822. {
  10823. ctx->bc.Instr(asBC_PshRPtr);
  10824. if( descr->returnType.IsObject() &&
  10825. !descr->returnType.IsObjectHandle() )
  10826. {
  10827. // We are getting the pointer to the object
  10828. // not a pointer to a object variable
  10829. ctx->type.dataType.MakeReference(false);
  10830. }
  10831. }
  10832. // A returned reference can be used as lvalue
  10833. ctx->type.isLValue = true;
  10834. }
  10835. else
  10836. {
  10837. asASSERT(useVariable == false);
  10838. if( descr->returnType.GetSizeInMemoryBytes() )
  10839. {
  10840. // Allocate a temporary variable to hold the value, but make sure
  10841. // the temporary variable isn't used in any of the deferred arguments
  10842. int l = int(reservedVariables.GetLength());
  10843. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  10844. {
  10845. asSExprContext *expr = (*args)[n]->origExpr;
  10846. if( expr )
  10847. expr->bc.GetVarsUsed(reservedVariables);
  10848. }
  10849. int offset = AllocateVariable(descr->returnType, true);
  10850. reservedVariables.SetLength(l);
  10851. ctx->type.SetVariable(descr->returnType, offset, true);
  10852. // Move the value from the return register to the variable
  10853. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  10854. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  10855. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  10856. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  10857. }
  10858. else
  10859. ctx->type.Set(descr->returnType);
  10860. ctx->type.isLValue = false;
  10861. // Clean up arguments
  10862. if( args )
  10863. AfterFunctionCall(funcId, *args, ctx, false);
  10864. ProcessDeferredParams(ctx);
  10865. }
  10866. }
  10867. // This only merges the bytecode, but doesn't modify the type of the final context
  10868. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  10869. {
  10870. before->bc.AddCode(&after->bc);
  10871. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  10872. {
  10873. before->deferredParams.PushLast(after->deferredParams[n]);
  10874. after->deferredParams[n].origExpr = 0;
  10875. }
  10876. after->deferredParams.SetLength(0);
  10877. }
  10878. // This merges both bytecode and the type of the final context
  10879. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  10880. {
  10881. MergeExprBytecode(before, after);
  10882. before->type = after->type;
  10883. before->property_get = after->property_get;
  10884. before->property_set = after->property_set;
  10885. before->property_const = after->property_const;
  10886. before->property_handle = after->property_handle;
  10887. before->property_ref = after->property_ref;
  10888. before->property_arg = after->property_arg;
  10889. before->exprNode = after->exprNode;
  10890. before->methodName = after->methodName;
  10891. after->property_arg = 0;
  10892. // Do not copy the origExpr member
  10893. }
  10894. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  10895. {
  10896. if( funcs.GetLength() == 0 ) return;
  10897. // This is only done for object methods
  10898. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  10899. if( desc->objectType == 0 ) return;
  10900. // Check if there are any non-const matches
  10901. asUINT n;
  10902. bool foundNonConst = false;
  10903. for( n = 0; n < funcs.GetLength(); n++ )
  10904. {
  10905. desc = builder->GetFunctionDescription(funcs[n]);
  10906. if( desc->isReadOnly != removeConst )
  10907. {
  10908. foundNonConst = true;
  10909. break;
  10910. }
  10911. }
  10912. if( foundNonConst )
  10913. {
  10914. // Remove all const methods
  10915. for( n = 0; n < funcs.GetLength(); n++ )
  10916. {
  10917. desc = builder->GetFunctionDescription(funcs[n]);
  10918. if( desc->isReadOnly == removeConst )
  10919. {
  10920. if( n == funcs.GetLength() - 1 )
  10921. funcs.PopLast();
  10922. else
  10923. funcs[n] = funcs.PopLast();
  10924. n--;
  10925. }
  10926. }
  10927. }
  10928. }
  10929. END_AS_NAMESPACE
  10930. #endif // AS_NO_COMPILER