as_compiler.cpp 348 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2011 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Öörni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf()
  30. #include "as_config.h"
  31. #include "as_compiler.h"
  32. #include "as_tokendef.h"
  33. #include "as_tokenizer.h"
  34. #include "as_string_util.h"
  35. #include "as_texts.h"
  36. #include "as_parser.h"
  37. BEGIN_AS_NAMESPACE
  38. // TODO: I must correct the interpretation of a references to objects in the compiler.
  39. // A reference should mean that a pointer to the object is on the stack.
  40. // No expression should end up as non-references to objects, as the actual object is
  41. // never put on the stack.
  42. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  43. // Function parameters of called functions can also be non-references, but in that case it means the
  44. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  45. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  46. {
  47. builder = 0;
  48. script = 0;
  49. variables = 0;
  50. isProcessingDeferredParams = false;
  51. isCompilingDefaultArg = false;
  52. noCodeOutput = 0;
  53. }
  54. asCCompiler::~asCCompiler()
  55. {
  56. while( variables )
  57. {
  58. asCVariableScope *var = variables;
  59. variables = variables->parent;
  60. asDELETE(var,asCVariableScope);
  61. }
  62. }
  63. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  64. {
  65. this->builder = builder;
  66. this->engine = builder->engine;
  67. this->script = script;
  68. this->outFunc = outFunc;
  69. hasCompileErrors = false;
  70. m_isConstructor = false;
  71. m_isConstructorCalled = false;
  72. nextLabel = 0;
  73. breakLabels.SetLength(0);
  74. continueLabels.SetLength(0);
  75. byteCode.ClearAll();
  76. }
  77. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc)
  78. {
  79. Reset(builder, script, outFunc);
  80. // Make sure all the class members can be initialized with default constructors
  81. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  82. {
  83. asCDataType &dt = outFunc->objectType->properties[n]->type;
  84. if( dt.IsObject() && !dt.IsObjectHandle() &&
  85. (((dt.GetObjectType()->flags & asOBJ_REF) && dt.GetObjectType()->beh.factory == 0) ||
  86. ((dt.GetObjectType()->flags & asOBJ_VALUE) && !(dt.GetObjectType()->flags & asOBJ_POD) && dt.GetObjectType()->beh.construct == 0)) )
  87. {
  88. asCString str;
  89. if( dt.GetFuncDef() )
  90. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  91. else
  92. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  93. Error(str.AddressOf(), node);
  94. }
  95. }
  96. // If the class is derived from another, then the base class' default constructor must be called
  97. if( outFunc->objectType->derivedFrom )
  98. {
  99. // Call the base class' default constructor
  100. byteCode.InstrSHORT(asBC_PSF, 0);
  101. byteCode.Instr(asBC_RDSPTR);
  102. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  103. }
  104. // Pop the object pointer from the stack
  105. byteCode.Ret(AS_PTR_SIZE);
  106. FinalizeFunction();
  107. #ifdef AS_DEBUG
  108. // DEBUG: output byte code
  109. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__dc.txt").AddressOf(), engine, outFunc);
  110. #endif
  111. return 0;
  112. }
  113. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  114. {
  115. Reset(builder, script, outFunc);
  116. unsigned int n;
  117. // Find the corresponding constructor
  118. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  119. int constructor = 0;
  120. for( n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  121. {
  122. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  123. {
  124. constructor = dt.GetBehaviour()->constructors[n];
  125. break;
  126. }
  127. }
  128. // Allocate the class and instanciate it with the constructor
  129. int varOffset = AllocateVariable(dt, true);
  130. byteCode.Push(AS_PTR_SIZE);
  131. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  132. // Copy all arguments to the top of the stack
  133. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  134. for( int a = argDwords-1; a >= 0; a-- )
  135. byteCode.InstrSHORT(asBC_PshV4, short(-a));
  136. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  137. // Return a handle to the newly created object
  138. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  139. byteCode.Ret(argDwords);
  140. FinalizeFunction();
  141. // Tell the virtual machine not to clean up parameters on exception
  142. outFunc->dontCleanUpOnException = true;
  143. /*
  144. #ifdef AS_DEBUG
  145. // DEBUG: output byte code
  146. asCString args;
  147. args.Format("%d", outFunc->parameterTypes.GetLength());
  148. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  149. #endif
  150. */
  151. return 0;
  152. }
  153. // Entry
  154. int asCCompiler::CompileTemplateFactoryStub(asCBuilder *builder, int trueFactoryId, asCObjectType *objType, asCScriptFunction *outFunc)
  155. {
  156. Reset(builder, 0, outFunc);
  157. asCScriptFunction *descr = builder->GetFunctionDescription(trueFactoryId);
  158. byteCode.InstrPTR(asBC_OBJTYPE, objType);
  159. byteCode.Call(asBC_CALLSYS, trueFactoryId, descr->GetSpaceNeededForArguments());
  160. byteCode.Ret(outFunc->GetSpaceNeededForArguments());
  161. FinalizeFunction();
  162. // Tell the virtual machine not to clean up the object on exception
  163. outFunc->dontCleanUpOnException = true;
  164. return 0;
  165. }
  166. // Entry
  167. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, sExplicitSignature *signature, asCScriptNode *func, asCScriptFunction *outFunc)
  168. {
  169. // TODO: The compiler should take the return type and parameter types from the
  170. // outFunc, instead of interpreting the script nodes again. The builder
  171. // must pass the list of parameter names. Making this change we can
  172. // eliminate large parts of this function and the sExplicitSignature structure
  173. Reset(builder, script, outFunc);
  174. int buildErrors = builder->numErrors;
  175. int stackPos = 0;
  176. if( outFunc->objectType )
  177. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  178. // Reserve a label for the cleanup code
  179. nextLabel++;
  180. // Add the first variable scope, which the parameters and
  181. // variables declared in the outermost statement block is
  182. // part of.
  183. AddVariableScope();
  184. asCScriptNode *node;
  185. bool isDestructor = false;
  186. asCDataType returnType;
  187. if( !signature )
  188. {
  189. // Skip the private keyword if it is there
  190. node = func->firstChild;
  191. if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
  192. node = node->next;
  193. //----------------------------------------------
  194. // Examine return type
  195. if( node->nodeType == snDataType )
  196. {
  197. returnType = builder->CreateDataTypeFromNode(node, script);
  198. returnType = builder->ModifyDataTypeFromNode(returnType, node->next, script, 0, 0);
  199. // Make sure the return type is instanciable or is void
  200. if( !returnType.CanBeInstanciated() &&
  201. returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  202. {
  203. asCString str;
  204. str.Format(TXT_DATA_TYPE_CANT_BE_s, returnType.Format().AddressOf());
  205. Error(str.AddressOf(), func->firstChild);
  206. }
  207. }
  208. else
  209. {
  210. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  211. if( node->tokenType == ttBitNot )
  212. isDestructor = true;
  213. else
  214. m_isConstructor = true;
  215. }
  216. }
  217. else
  218. {
  219. node = func;
  220. returnType = signature->returnType;
  221. }
  222. #ifndef AS_OLD
  223. // If the return type is a value type returned by value the address of the
  224. // location where the value will be stored is pushed on the stack before
  225. // the arguments
  226. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  227. stackPos -= AS_PTR_SIZE;
  228. #endif
  229. asCVariableScope vs(0);
  230. if( !signature )
  231. {
  232. //----------------------------------------------
  233. // Declare parameters
  234. // Find first parameter
  235. while( node && node->nodeType != snParameterList )
  236. node = node->next;
  237. // Register parameters from last to first, otherwise they will be destroyed in the wrong order
  238. if( node ) node = node->firstChild;
  239. while( node )
  240. {
  241. // Get the parameter type
  242. asCDataType type = builder->CreateDataTypeFromNode(node, script);
  243. asETypeModifiers inoutFlag = asTM_NONE;
  244. type = builder->ModifyDataTypeFromNode(type, node->next, script, &inoutFlag, 0);
  245. // Is the data type allowed?
  246. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  247. (!type.IsReference() && !type.CanBeInstanciated()) )
  248. {
  249. asCString str;
  250. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  251. Error(str.AddressOf(), node);
  252. }
  253. // If the parameter has a name then declare it as variable
  254. node = node->next->next;
  255. if( node && node->nodeType == snIdentifier )
  256. {
  257. asCString name(&script->code[node->tokenPos], node->tokenLength);
  258. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  259. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  260. // Add marker for variable declaration
  261. byteCode.VarDecl((int)outFunc->variables.GetLength());
  262. outFunc->AddVariable(name, type, stackPos);
  263. node = node->next;
  264. // Skip the default arg
  265. if( node && node->nodeType == snExpression )
  266. node = node->next;
  267. }
  268. else
  269. vs.DeclareVariable("", type, stackPos, true);
  270. // Move to next parameter
  271. stackPos -= type.GetSizeOnStackDWords();
  272. }
  273. }
  274. else
  275. {
  276. asCArray<asCDataType> &args = signature->argTypes;
  277. asCArray<asETypeModifiers> &inoutFlags = signature->argModifiers;
  278. asCArray<asCString> &argNames = signature->argNames;
  279. asASSERT(args.GetLength() == argNames.GetLength());
  280. for( int k = 0; k < (int)args.GetLength(); k++ )
  281. {
  282. asCDataType type = args[k];
  283. asETypeModifiers inoutFlag = inoutFlags[k];
  284. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  285. (!type.IsReference() && !type.CanBeInstanciated()) )
  286. {
  287. asCString str;
  288. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  289. Error(str.AddressOf(), node);
  290. }
  291. if( 0 != argNames[k].Compare("") )
  292. {
  293. if( vs.DeclareVariable(argNames[k].AddressOf(), type, stackPos, true) < 0 )
  294. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  295. // Add marker for variable declaration
  296. byteCode.VarDecl((int)outFunc->variables.GetLength());
  297. outFunc->AddVariable(argNames[k], type, stackPos);
  298. }
  299. else
  300. vs.DeclareVariable("", type, stackPos, true);
  301. // Move to next parameter
  302. stackPos -= type.GetSizeOnStackDWords();
  303. }
  304. }
  305. int n;
  306. for( n = (int)vs.variables.GetLength() - 1; n >= 0; n-- )
  307. {
  308. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  309. }
  310. // Is the return type allowed?
  311. if( (returnType.GetSizeOnStackDWords() == 0 && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  312. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  313. {
  314. asCString str;
  315. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  316. Error(str.AddressOf(), func);
  317. }
  318. variables->DeclareVariable("return", returnType, stackPos, true);
  319. //--------------------------------------------
  320. // Compile the statement block
  321. // We need to parse the statement block now
  322. asCScriptNode *blockBegin;
  323. if( !signature )
  324. blockBegin = func->lastChild;
  325. else
  326. blockBegin = func;
  327. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  328. asCParser parser(builder);
  329. int r = parser.ParseStatementBlock(script, blockBegin);
  330. if( r < 0 ) return -1;
  331. asCScriptNode *block = parser.GetScriptNode();
  332. bool hasReturn;
  333. asCByteCode bc(engine);
  334. LineInstr(&bc, blockBegin->tokenPos);
  335. CompileStatementBlock(block, false, &hasReturn, &bc);
  336. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  337. // Make sure there is a return in all paths (if not return type is void)
  338. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  339. {
  340. if( hasReturn == false )
  341. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  342. }
  343. //------------------------------------------------
  344. // Concatenate the bytecode
  345. // Insert a JitEntry at the start of the function for JIT compilers
  346. byteCode.InstrPTR(asBC_JitEntry, 0);
  347. // Count total variable size
  348. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  349. byteCode.Push(varSize);
  350. if( outFunc->objectType )
  351. {
  352. // Call the base class' default constructor unless called manually in the code
  353. if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
  354. {
  355. byteCode.InstrSHORT(asBC_PSF, 0);
  356. byteCode.Instr(asBC_RDSPTR);
  357. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  358. }
  359. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  360. // TODO: optimize: This is probably not necessary for constructors as no outside reference to the object is created yet
  361. byteCode.InstrSHORT(asBC_PSF, 0);
  362. byteCode.Instr(asBC_RDSPTR);
  363. byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  364. }
  365. // Add the code for the statement block
  366. byteCode.AddCode(&bc);
  367. // Deallocate all local variables
  368. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  369. {
  370. sVariable *v = variables->variables[n];
  371. if( v->stackOffset > 0 )
  372. {
  373. // Call variables destructors
  374. if( v->name != "return" && v->name != "return address" )
  375. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  376. DeallocateVariable(v->stackOffset);
  377. }
  378. }
  379. // This is the label that return statements jump to
  380. // in order to exit the function
  381. byteCode.Label(0);
  382. // Call destructors for function parameters
  383. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  384. {
  385. sVariable *v = variables->variables[n];
  386. if( v->stackOffset <= 0 )
  387. {
  388. // Call variable destructors here, for variables not yet destroyed
  389. if( v->name != "return" && v->name != "return address" )
  390. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  391. }
  392. // Do not deallocate parameters
  393. }
  394. // Release the object pointer again
  395. if( outFunc->objectType )
  396. {
  397. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  398. }
  399. // If there are compile errors, there is no reason to build the final code
  400. if( hasCompileErrors || builder->numErrors != buildErrors )
  401. return -1;
  402. // At this point there should be no variables allocated
  403. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  404. // Remove the variable scope
  405. RemoveVariableScope();
  406. // This POP is not necessary as the return will clean up the stack frame anyway.
  407. // The bytecode optimizer would remove this POP, however by not including it here
  408. // it is guaranteed it doesn't have to be adjusted by the asCRestore class when
  409. // a types are of a different size than originally compiled for.
  410. // byteCode.Pop(varSize);
  411. byteCode.Ret(-stackPos);
  412. FinalizeFunction();
  413. #ifdef AS_DEBUG
  414. // DEBUG: output byte code
  415. if( outFunc->objectType )
  416. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  417. else
  418. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  419. #endif
  420. return 0;
  421. }
  422. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  423. {
  424. if( !type.IsObject() )
  425. return 0;
  426. // CallCopyConstructor should not be called for object handles.
  427. asASSERT( !type.IsObjectHandle() );
  428. asCArray<asSExprContext*> args;
  429. args.PushLast(arg);
  430. // The reference parameter must be pushed on the stack
  431. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  432. // Since we're calling the copy constructor, we have to trust the function to not do
  433. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  434. // copies of the argument in order to guarantee safety.
  435. if( type.GetObjectType()->flags & asOBJ_REF )
  436. {
  437. asSExprContext ctx(engine);
  438. int func = 0;
  439. asSTypeBehaviour *beh = type.GetBehaviour();
  440. if( beh ) func = beh->copyfactory;
  441. if( func > 0 )
  442. {
  443. if( !isGlobalVar )
  444. {
  445. // Call factory and store the handle in the given variable
  446. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  447. // Pop the reference left by the function call
  448. ctx.bc.Pop(AS_PTR_SIZE);
  449. }
  450. else
  451. {
  452. // Call factory
  453. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  454. // Store the returned handle in the global variable
  455. ctx.bc.Instr(asBC_RDSPTR);
  456. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  457. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  458. ctx.bc.Pop(AS_PTR_SIZE);
  459. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  460. }
  461. bc->AddCode(&ctx.bc);
  462. return 0;
  463. }
  464. }
  465. else
  466. {
  467. asSTypeBehaviour *beh = type.GetBehaviour();
  468. int func = beh ? beh->copyconstruct : 0;
  469. if( func > 0 )
  470. {
  471. // Push the address where the object will be stored on the stack, before the argument
  472. // TODO: When the context is serializable this probably has to be changed, since this
  473. // pointer can remain on the stack while the context is suspended. There is no
  474. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  475. asCByteCode tmp(engine);
  476. if( isGlobalVar )
  477. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  478. else if( isObjectOnHeap )
  479. tmp.InstrSHORT(asBC_PSF, (short)offset);
  480. tmp.AddCode(bc);
  481. bc->AddCode(&tmp);
  482. // When the object is allocated on the stack the object pointer
  483. // must be pushed on the stack after the arguments
  484. if( !isObjectOnHeap )
  485. {
  486. asASSERT( !isGlobalVar );
  487. bc->InstrSHORT(asBC_PSF, (short)offset);
  488. if( derefDest )
  489. {
  490. // The variable is a reference to the real location, so we need to dereference it
  491. bc->Instr(asBC_RDSPTR);
  492. }
  493. }
  494. asSExprContext ctx(engine);
  495. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  496. bc->AddCode(&ctx.bc);
  497. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  498. // Mark the object as initialized
  499. if( !isObjectOnHeap )
  500. bc->ObjInfo(offset, asOBJ_INIT);
  501. return 0;
  502. }
  503. }
  504. // Class has no copy constructor/factory.
  505. asCString str;
  506. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  507. Error(str.AddressOf(), node);
  508. return -1;
  509. }
  510. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, bool isGlobalVar, bool deferDest)
  511. {
  512. if( !type.IsObject() || type.IsObjectHandle() )
  513. return 0;
  514. if( type.GetObjectType()->flags & asOBJ_REF )
  515. {
  516. asSExprContext ctx(engine);
  517. ctx.exprNode = node;
  518. int func = 0;
  519. asSTypeBehaviour *beh = type.GetBehaviour();
  520. if( beh ) func = beh->factory;
  521. if( func > 0 )
  522. {
  523. if( !isGlobalVar )
  524. {
  525. // Call factory and store the handle in the given variable
  526. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  527. // Pop the reference left by the function call
  528. ctx.bc.Pop(AS_PTR_SIZE);
  529. }
  530. else
  531. {
  532. // Call factory
  533. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  534. // Store the returned handle in the global variable
  535. ctx.bc.Instr(asBC_RDSPTR);
  536. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  537. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  538. ctx.bc.Pop(AS_PTR_SIZE);
  539. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  540. }
  541. bc->AddCode(&ctx.bc);
  542. return 0;
  543. }
  544. }
  545. else
  546. {
  547. asSTypeBehaviour *beh = type.GetBehaviour();
  548. int func = 0;
  549. if( beh ) func = beh->construct;
  550. // Allocate and initialize with the default constructor
  551. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  552. {
  553. if( !isObjectOnHeap )
  554. {
  555. asASSERT( !isGlobalVar );
  556. // There is nothing to do if there is no function,
  557. // as the memory is already allocated on the stack
  558. if( func )
  559. {
  560. // Call the constructor as a normal function
  561. bc->InstrSHORT(asBC_PSF, (short)offset);
  562. if( deferDest )
  563. bc->Instr(asBC_RDSPTR);
  564. asSExprContext ctx(engine);
  565. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  566. bc->AddCode(&ctx.bc);
  567. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  568. // Mark the object as initialized
  569. bc->ObjInfo(offset, asOBJ_INIT);
  570. }
  571. }
  572. else
  573. {
  574. if( isGlobalVar )
  575. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  576. else
  577. bc->InstrSHORT(asBC_PSF, (short)offset);
  578. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  579. }
  580. return 0;
  581. }
  582. }
  583. // Class has no default factory/constructor.
  584. asCString str;
  585. // TODO: funcdef: asCDataType should have a GetTypeName()
  586. if( type.GetFuncDef() )
  587. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  588. else
  589. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  590. Error(str.AddressOf(), node);
  591. return -1;
  592. }
  593. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  594. {
  595. if( !type.IsReference() )
  596. {
  597. // Call destructor for the data type
  598. if( type.IsObject() )
  599. {
  600. if( isObjectOnHeap || type.IsObjectHandle() )
  601. {
  602. // Free the memory
  603. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  604. }
  605. else
  606. {
  607. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  608. if( type.GetBehaviour()->destruct )
  609. {
  610. // Call the destructor as a regular function
  611. bc->InstrSHORT(asBC_PSF, (short)offset);
  612. asSExprContext ctx(engine);
  613. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  614. bc->AddCode(&ctx.bc);
  615. }
  616. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  617. // Mark the object as destroyed
  618. bc->ObjInfo(offset, asOBJ_UNINIT);
  619. }
  620. }
  621. }
  622. }
  623. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  624. {
  625. int r, c;
  626. script->ConvertPosToRowCol(pos, &r, &c);
  627. bc->Line(r, c);
  628. }
  629. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  630. {
  631. *hasReturn = false;
  632. bool isFinished = false;
  633. bool hasWarned = false;
  634. if( ownVariableScope )
  635. {
  636. bc->Block(true);
  637. AddVariableScope();
  638. }
  639. asCScriptNode *node = block->firstChild;
  640. while( node )
  641. {
  642. if( !hasWarned && (*hasReturn || isFinished) )
  643. {
  644. hasWarned = true;
  645. Warning(TXT_UNREACHABLE_CODE, node);
  646. }
  647. if( node->nodeType == snBreak || node->nodeType == snContinue )
  648. isFinished = true;
  649. asCByteCode statement(engine);
  650. if( node->nodeType == snDeclaration )
  651. CompileDeclaration(node, &statement);
  652. else
  653. CompileStatement(node, hasReturn, &statement);
  654. LineInstr(bc, node->tokenPos);
  655. bc->AddCode(&statement);
  656. if( !hasCompileErrors )
  657. {
  658. asASSERT( tempVariables.GetLength() == 0 );
  659. asASSERT( reservedVariables.GetLength() == 0 );
  660. }
  661. node = node->next;
  662. }
  663. if( ownVariableScope )
  664. {
  665. // Deallocate variables in this block, in reverse order
  666. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  667. {
  668. sVariable *v = variables->variables[n];
  669. // Call variable destructors here, for variables not yet destroyed
  670. // If the block is terminated with a break, continue, or
  671. // return the variables are already destroyed
  672. if( !isFinished && !*hasReturn )
  673. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  674. // Don't deallocate function parameters
  675. if( v->stackOffset > 0 )
  676. DeallocateVariable(v->stackOffset);
  677. }
  678. RemoveVariableScope();
  679. bc->Block(false);
  680. }
  681. }
  682. // Entry
  683. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  684. {
  685. Reset(builder, script, outFunc);
  686. // Add a variable scope (even though variables can't be declared)
  687. AddVariableScope();
  688. asSExprContext ctx(engine);
  689. gvar->isPureConstant = false;
  690. // Parse the initialization nodes
  691. asCParser parser(builder);
  692. if( node )
  693. {
  694. int r = parser.ParseGlobalVarInit(script, node);
  695. if( r < 0 )
  696. return r;
  697. node = parser.GetScriptNode();
  698. }
  699. // Compile the expression
  700. if( node && node->nodeType == snArgList )
  701. {
  702. // Make sure that it is a registered type, and that it isn't a pointer
  703. if( gvar->datatype.GetObjectType() == 0 || gvar->datatype.IsObjectHandle() )
  704. {
  705. Error(TXT_MUST_BE_OBJECT, node);
  706. }
  707. else
  708. {
  709. // Compile the arguments
  710. asCArray<asSExprContext *> args;
  711. if( CompileArgumentList(node, args) >= 0 )
  712. {
  713. // Find all constructors
  714. asCArray<int> funcs;
  715. asSTypeBehaviour *beh = gvar->datatype.GetBehaviour();
  716. if( beh )
  717. {
  718. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  719. funcs = beh->factories;
  720. else
  721. funcs = beh->constructors;
  722. }
  723. asCString str = gvar->datatype.Format();
  724. MatchFunctions(funcs, args, node, str.AddressOf());
  725. if( funcs.GetLength() == 1 )
  726. {
  727. int r = asSUCCESS;
  728. // Add the default values for arguments not explicitly supplied
  729. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  730. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  731. r = CompileDefaultArgs(node, args, func);
  732. if( r == asSUCCESS )
  733. {
  734. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  735. {
  736. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  737. // Store the returned handle in the global variable
  738. ctx.bc.Instr(asBC_RDSPTR);
  739. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  740. ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
  741. ctx.bc.Pop(AS_PTR_SIZE);
  742. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  743. }
  744. else
  745. {
  746. // Push the address of the location where the variable will be stored on the stack.
  747. // This reference is safe, because the addresses of the global variables cannot change.
  748. // TODO: When serialization of the context is implemented this will probably have to change,
  749. // because this pointer may be on the stack while the context is suspended, and may
  750. // be difficult to serialize as the context doesn't know that the value represents a
  751. // pointer.
  752. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  753. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  754. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  755. PerformFunctionCall(funcs[0], &ctx, true, &args, gvar->datatype.GetObjectType());
  756. }
  757. }
  758. }
  759. }
  760. // Cleanup
  761. for( asUINT n = 0; n < args.GetLength(); n++ )
  762. if( args[n] )
  763. {
  764. asDELETE(args[n],asSExprContext);
  765. }
  766. }
  767. }
  768. else if( node && node->nodeType == snInitList )
  769. {
  770. asCTypeInfo ti;
  771. ti.Set(gvar->datatype);
  772. ti.isVariable = false;
  773. ti.isTemporary = false;
  774. ti.stackOffset = (short)gvar->index;
  775. ti.isLValue = true;
  776. CompileInitList(&ti, node, &ctx.bc);
  777. node = node->next;
  778. }
  779. else if( node )
  780. {
  781. // Compile the right hand expression
  782. asSExprContext expr(engine);
  783. int r = CompileAssignment(node, &expr); if( r < 0 ) return r;
  784. // Assign the value to the variable
  785. if( gvar->datatype.IsPrimitive() )
  786. {
  787. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  788. {
  789. ImplicitConversion(&expr, gvar->datatype, node, asIC_IMPLICIT_CONV);
  790. gvar->isPureConstant = true;
  791. gvar->constantValue = expr.type.qwordValue;
  792. }
  793. asSExprContext lctx(engine);
  794. lctx.type.Set(gvar->datatype);
  795. lctx.type.dataType.MakeReference(true);
  796. lctx.type.dataType.MakeReadOnly(false);
  797. lctx.type.isLValue = true;
  798. // If it is an enum value that is being compiled, then
  799. // we skip this, as the bytecode won't be used anyway
  800. if( !gvar->isEnumValue )
  801. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[gvar->index]->GetAddressOfValue());
  802. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  803. }
  804. else
  805. {
  806. // TODO: optimize: Here we should look for the best matching constructor, instead of
  807. // just the copy constructor. Only if no appropriate constructor is
  808. // available should the assignment operator be used.
  809. if( !gvar->datatype.IsObjectHandle() )
  810. {
  811. // Call the default constructor to have a valid object for the assignment
  812. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  813. }
  814. asSExprContext lexpr(engine);
  815. lexpr.type.Set(gvar->datatype);
  816. lexpr.type.dataType.MakeReference(true);
  817. lexpr.type.dataType.MakeReadOnly(false);
  818. lexpr.type.stackOffset = -1;
  819. lexpr.type.isLValue = true;
  820. if( gvar->datatype.IsObjectHandle() )
  821. lexpr.type.isExplicitHandle = true;
  822. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  823. // If left expression resolves into a registered type
  824. // check if the assignment operator is overloaded, and check
  825. // the type of the right hand expression. If none is found
  826. // the default action is a direct copy if it is the same type
  827. // and a simple assignment.
  828. bool assigned = false;
  829. // Even though an ASHANDLE can be an explicit handle the assignment needs to be treated by the overloaded operator
  830. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  831. {
  832. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  833. if( assigned )
  834. {
  835. // Pop the resulting value
  836. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  837. // Release the argument
  838. ProcessDeferredParams(&ctx);
  839. }
  840. }
  841. if( !assigned )
  842. {
  843. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  844. // If the expression is constant and the variable also is constant
  845. // then mark the variable as pure constant. This will allow the compiler
  846. // to optimize expressions with this variable.
  847. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  848. {
  849. gvar->isPureConstant = true;
  850. gvar->constantValue = expr.type.qwordValue;
  851. }
  852. // Add expression code to bytecode
  853. MergeExprBytecode(&ctx, &expr);
  854. // Add byte code for storing value of expression in variable
  855. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  856. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node);
  857. // Release temporary variables used by expression
  858. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  859. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  860. }
  861. }
  862. }
  863. else if( gvar->datatype.IsObject() && !gvar->datatype.IsObjectHandle() )
  864. {
  865. // Call the default constructor in case no explicit initialization is given
  866. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  867. }
  868. // Concatenate the bytecode
  869. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  870. // Add information on the line number for the global variable
  871. size_t pos = 0;
  872. if( gvar->idNode )
  873. pos = gvar->idNode->tokenPos;
  874. else if( gvar->nextNode )
  875. pos = gvar->nextNode->tokenPos;
  876. LineInstr(&byteCode, pos);
  877. // We need to push zeroes on the stack to guarantee
  878. // that temporary object handles are clear
  879. int n;
  880. for( n = 0; n < varSize; n++ )
  881. byteCode.InstrINT(asBC_PshC4, 0);
  882. byteCode.AddCode(&ctx.bc);
  883. // Deallocate variables in this block, in reverse order
  884. for( n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  885. {
  886. sVariable *v = variables->variables[n];
  887. // Call variable destructors here, for variables not yet destroyed
  888. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  889. DeallocateVariable(v->stackOffset);
  890. }
  891. if( hasCompileErrors ) return -1;
  892. // At this point there should be no variables allocated
  893. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  894. // Remove the variable scope again
  895. RemoveVariableScope();
  896. byteCode.Ret(0);
  897. FinalizeFunction();
  898. #ifdef AS_DEBUG
  899. // DEBUG: output byte code
  900. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  901. #endif
  902. return 0;
  903. }
  904. void asCCompiler::FinalizeFunction()
  905. {
  906. asUINT n;
  907. // Tell the bytecode which variables are temporary
  908. for( n = 0; n < variableIsTemporary.GetLength(); n++ )
  909. {
  910. if( variableIsTemporary[n] )
  911. byteCode.DefineTemporaryVariable(GetVariableOffset(n));
  912. }
  913. // Finalize the bytecode
  914. byteCode.Finalize();
  915. byteCode.ExtractObjectVariableInfo(outFunc);
  916. // Compile the list of object variables for the exception handler
  917. for( n = 0; n < variableAllocations.GetLength(); n++ )
  918. {
  919. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  920. {
  921. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  922. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  923. outFunc->objVariableIsOnHeap.PushLast(variableIsOnHeap[n]);
  924. }
  925. }
  926. // Copy byte code to the function
  927. outFunc->byteCode.SetLength(byteCode.GetSize());
  928. byteCode.Output(outFunc->byteCode.AddressOf());
  929. outFunc->AddReferences();
  930. outFunc->stackNeeded = byteCode.largestStackUsed;
  931. outFunc->lineNumbers = byteCode.lineNumbers;
  932. }
  933. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  934. {
  935. asCDataType param = *paramType;
  936. if( paramType->GetTokenType() == ttQuestion )
  937. {
  938. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  939. param = ctx->type.dataType;
  940. param.MakeHandle(ctx->type.isExplicitHandle);
  941. param.MakeReference(paramType->IsReference());
  942. param.MakeReadOnly(paramType->IsReadOnly());
  943. }
  944. else
  945. param = *paramType;
  946. asCDataType dt = param;
  947. // Need to protect arguments by reference
  948. if( isFunction && dt.IsReference() )
  949. {
  950. if( paramType->GetTokenType() == ttQuestion )
  951. {
  952. asCByteCode tmpBC(engine);
  953. // Place the type id on the stack as a hidden parameter
  954. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  955. // Insert the code before the expression code
  956. tmpBC.AddCode(&ctx->bc);
  957. ctx->bc.AddCode(&tmpBC);
  958. }
  959. // Allocate a temporary variable of the same type as the argument
  960. dt.MakeReference(false);
  961. dt.MakeReadOnly(false);
  962. int offset;
  963. if( refType == 1 ) // &in
  964. {
  965. ProcessPropertyGetAccessor(ctx, node);
  966. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  967. // Even if the same variable is passed in another argument as non-const then there is no problem
  968. if( dt.IsPrimitive() || dt.IsNullHandle() )
  969. {
  970. IsVariableInitialized(&ctx->type, node);
  971. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  972. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  973. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  974. ConvertToTempVariable(ctx);
  975. PushVariableOnStack(ctx, true);
  976. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  977. }
  978. else
  979. {
  980. IsVariableInitialized(&ctx->type, node);
  981. if( !isMakingCopy )
  982. {
  983. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true);
  984. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  985. {
  986. asCString str;
  987. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  988. Error(str.AddressOf(), node);
  989. ctx->type.Set(param);
  990. }
  991. }
  992. // If the argument already is a temporary
  993. // variable we don't need to allocate another
  994. // If the parameter is read-only and the object already is a local
  995. // variable then it is not necessary to make a copy either
  996. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
  997. {
  998. // Make sure the variable is not used in the expression
  999. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1000. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  1001. // Allocate and construct the temporary object
  1002. asCByteCode tmpBC(engine);
  1003. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1004. // Insert the code before the expression code
  1005. tmpBC.AddCode(&ctx->bc);
  1006. ctx->bc.AddCode(&tmpBC);
  1007. // Assign the evaluated expression to the temporary variable
  1008. PrepareForAssignment(&dt, ctx, node, true);
  1009. dt.MakeReference(IsVariableOnHeap(offset));
  1010. asCTypeInfo type;
  1011. type.Set(dt);
  1012. type.isTemporary = true;
  1013. type.stackOffset = (short)offset;
  1014. if( dt.IsObjectHandle() )
  1015. type.isExplicitHandle = true;
  1016. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1017. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  1018. ctx->bc.Pop(ctx->type.dataType.GetSizeOnStackDWords());
  1019. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  1020. ctx->type = type;
  1021. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1022. if( dt.IsObject() && !dt.IsObjectHandle() )
  1023. ctx->bc.Instr(asBC_RDSPTR);
  1024. if( paramType->IsReadOnly() )
  1025. ctx->type.dataType.MakeReadOnly(true);
  1026. }
  1027. else if( isMakingCopy )
  1028. {
  1029. // We must guarantee that the address to the value is on the stack
  1030. if( ctx->type.dataType.IsObject() &&
  1031. !ctx->type.dataType.IsObjectHandle() &&
  1032. ctx->type.dataType.IsReference() )
  1033. Dereference(ctx, true);
  1034. }
  1035. }
  1036. }
  1037. else if( refType == 2 ) // &out
  1038. {
  1039. // Make sure the variable is not used in the expression
  1040. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1041. if( dt.IsPrimitive() )
  1042. {
  1043. ctx->type.SetVariable(dt, offset, true);
  1044. PushVariableOnStack(ctx, true);
  1045. }
  1046. else
  1047. {
  1048. // Allocate and construct the temporary object
  1049. asCByteCode tmpBC(engine);
  1050. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1051. // Insert the code before the expression code
  1052. tmpBC.AddCode(&ctx->bc);
  1053. ctx->bc.AddCode(&tmpBC);
  1054. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  1055. asCTypeInfo type;
  1056. type.Set(dt);
  1057. type.isTemporary = true;
  1058. type.stackOffset = (short)offset;
  1059. ctx->type = type;
  1060. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1061. if( dt.IsObject() && !dt.IsObjectHandle() )
  1062. ctx->bc.Instr(asBC_RDSPTR);
  1063. }
  1064. // After the function returns the temporary variable will
  1065. // be assigned to the expression, if it is a valid lvalue
  1066. }
  1067. else if( refType == asTM_INOUTREF )
  1068. {
  1069. ProcessPropertyGetAccessor(ctx, node);
  1070. // Literal constants cannot be passed to inout ref arguments
  1071. if( !ctx->type.isVariable && ctx->type.isConstant )
  1072. {
  1073. Error(TXT_NOT_VALID_REFERENCE, node);
  1074. }
  1075. // Only objects that support object handles
  1076. // can be guaranteed to be safe. Local variables are
  1077. // already safe, so there is no need to add an extra
  1078. // references
  1079. if( !engine->ep.allowUnsafeReferences &&
  1080. !ctx->type.isVariable &&
  1081. ctx->type.dataType.IsObject() &&
  1082. !ctx->type.dataType.IsObjectHandle() &&
  1083. ctx->type.dataType.GetBehaviour()->addref &&
  1084. ctx->type.dataType.GetBehaviour()->release )
  1085. {
  1086. // Store a handle to the object as local variable
  1087. asSExprContext tmp(engine);
  1088. asCDataType dt = ctx->type.dataType;
  1089. dt.MakeHandle(true);
  1090. dt.MakeReference(false);
  1091. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1092. // Copy the handle
  1093. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1094. ctx->bc.Instr(asBC_RDSPTR);
  1095. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1096. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1097. ctx->bc.Pop(AS_PTR_SIZE);
  1098. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1099. dt.MakeHandle(false);
  1100. dt.MakeReference(true);
  1101. // Release previous temporary variable stored in the context (if any)
  1102. if( ctx->type.isTemporary )
  1103. {
  1104. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1105. }
  1106. ctx->type.SetVariable(dt, offset, true);
  1107. }
  1108. // Make sure the reference to the value is on the stack
  1109. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1110. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1111. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !paramType->IsObjectHandle() )
  1112. Dereference(ctx, true);
  1113. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1114. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1115. else if( ctx->type.dataType.IsPrimitive() )
  1116. ctx->bc.Instr(asBC_PshRPtr);
  1117. }
  1118. }
  1119. else
  1120. {
  1121. ProcessPropertyGetAccessor(ctx, node);
  1122. if( dt.IsPrimitive() )
  1123. {
  1124. IsVariableInitialized(&ctx->type, node);
  1125. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1126. // Implicitly convert primitives to the parameter type
  1127. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1128. if( ctx->type.isVariable )
  1129. {
  1130. PushVariableOnStack(ctx, dt.IsReference());
  1131. }
  1132. else if( ctx->type.isConstant )
  1133. {
  1134. ConvertToVariable(ctx);
  1135. PushVariableOnStack(ctx, dt.IsReference());
  1136. }
  1137. }
  1138. else
  1139. {
  1140. IsVariableInitialized(&ctx->type, node);
  1141. // Implicitly convert primitives to the parameter type
  1142. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1143. // Was the conversion successful?
  1144. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1145. {
  1146. asCString str;
  1147. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1148. Error(str.AddressOf(), node);
  1149. ctx->type.Set(dt);
  1150. }
  1151. if( dt.IsObjectHandle() )
  1152. ctx->type.isExplicitHandle = true;
  1153. if( dt.IsObject() )
  1154. {
  1155. if( !dt.IsReference() )
  1156. {
  1157. // Objects passed by value must be placed in temporary variables
  1158. // so that they are guaranteed to not be referenced anywhere else.
  1159. // The object must also be allocated on the heap, as the memory will
  1160. // be deleted by in as_callfunc_xxx.
  1161. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1162. PrepareTemporaryObject(node, ctx, true);
  1163. // The implicit conversion shouldn't convert the object to
  1164. // non-reference yet. It will be dereferenced just before the call.
  1165. // Otherwise the object might be missed by the exception handler.
  1166. dt.MakeReference(true);
  1167. }
  1168. else
  1169. {
  1170. // An object passed by reference should place the pointer to
  1171. // the object on the stack.
  1172. dt.MakeReference(false);
  1173. }
  1174. }
  1175. }
  1176. }
  1177. // Don't put any pointer on the stack yet
  1178. if( param.IsReference() || param.IsObject() )
  1179. {
  1180. // &inout parameter may leave the reference on the stack already
  1181. if( refType != 3 )
  1182. {
  1183. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1184. if( ctx->type.isVariable || ctx->type.isTemporary )
  1185. {
  1186. ctx->bc.Pop(AS_PTR_SIZE);
  1187. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1188. ProcessDeferredParams(ctx);
  1189. }
  1190. }
  1191. }
  1192. }
  1193. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1194. {
  1195. // When a match has been found, compile the final byte code using correct parameter types
  1196. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1197. // If the function being called is the opAssign or copy constructor for the same type
  1198. // as the argument, then we should avoid making temporary copy of the argument
  1199. bool makingCopy = false;
  1200. if( descr->parameterTypes.GetLength() == 1 &&
  1201. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1202. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1203. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1204. makingCopy = true;
  1205. // Add code for arguments
  1206. asSExprContext e(engine);
  1207. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1208. {
  1209. // Make sure PrepareArgument doesn't use any variable that is already
  1210. // being used by any of the following argument expressions
  1211. int l = reservedVariables.GetLength();
  1212. for( int m = n-1; m >= 0; m-- )
  1213. args[m]->bc.GetVarsUsed(reservedVariables);
  1214. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1215. reservedVariables.SetLength(l);
  1216. }
  1217. bc->AddCode(&e.bc);
  1218. }
  1219. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1220. {
  1221. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1222. int offset = 0;
  1223. if( addOneToOffset )
  1224. offset += AS_PTR_SIZE;
  1225. #ifndef AS_OLD
  1226. // The address of where the return value should be stored is push on top of the arguments
  1227. if( descr->DoesReturnOnStack() )
  1228. offset += AS_PTR_SIZE;
  1229. #endif
  1230. // If the function being called is the opAssign or copy constructor for the same type
  1231. // as the argument, then we should avoid making temporary copy of the argument
  1232. bool makingCopy = false;
  1233. if( descr->parameterTypes.GetLength() == 1 &&
  1234. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1235. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1236. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1237. makingCopy = true;
  1238. // Move the objects that are sent by value to the stack just before the call
  1239. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1240. {
  1241. if( descr->parameterTypes[n].IsReference() )
  1242. {
  1243. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1244. {
  1245. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1246. {
  1247. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1248. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1249. {
  1250. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1251. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1252. // as the value allocated on the stack is guaranteed to be safe
  1253. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1254. else
  1255. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1256. }
  1257. }
  1258. if( args[n]->type.dataType.IsObjectHandle() )
  1259. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1260. }
  1261. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1262. {
  1263. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1264. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1265. {
  1266. // Send the object as a reference to the object,
  1267. // and not to the variable holding the object
  1268. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1269. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1270. // as the value allocated on the stack is guaranteed to be safe
  1271. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1272. else
  1273. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1274. }
  1275. else
  1276. {
  1277. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1278. }
  1279. }
  1280. }
  1281. else if( descr->parameterTypes[n].IsObject() )
  1282. {
  1283. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1284. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1285. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1286. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1287. // The temporary variable must not be freed as it will no longer hold an object
  1288. DeallocateVariable(args[n]->type.stackOffset);
  1289. args[n]->type.isTemporary = false;
  1290. }
  1291. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1292. }
  1293. }
  1294. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1295. {
  1296. asASSERT(node->nodeType == snArgList);
  1297. // Count arguments
  1298. asCScriptNode *arg = node->firstChild;
  1299. int argCount = 0;
  1300. while( arg )
  1301. {
  1302. argCount++;
  1303. arg = arg->next;
  1304. }
  1305. // Prepare the arrays
  1306. args.SetLength(argCount);
  1307. int n;
  1308. for( n = 0; n < argCount; n++ )
  1309. args[n] = 0;
  1310. n = argCount-1;
  1311. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1312. bool anyErrors = false;
  1313. arg = node->lastChild;
  1314. while( arg )
  1315. {
  1316. asSExprContext expr(engine);
  1317. int r = CompileAssignment(arg, &expr);
  1318. if( r < 0 ) anyErrors = true;
  1319. args[n] = asNEW(asSExprContext)(engine);
  1320. MergeExprBytecodeAndType(args[n], &expr);
  1321. n--;
  1322. arg = arg->prev;
  1323. }
  1324. return anyErrors ? -1 : 0;
  1325. }
  1326. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1327. {
  1328. bool anyErrors = false;
  1329. asCArray<int> varsUsed;
  1330. int explicitArgs = (int)args.GetLength();
  1331. for( int p = 0; p < explicitArgs; p++ )
  1332. args[p]->bc.GetVarsUsed(varsUsed);
  1333. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1334. args.SetLength(func->parameterTypes.GetLength());
  1335. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1336. args[c] = 0;
  1337. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1338. {
  1339. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1340. // Parse the default arg string
  1341. asCParser parser(builder);
  1342. asCScriptCode code;
  1343. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1344. int r = parser.ParseExpression(&code);
  1345. if( r < 0 ) { anyErrors = true; continue; }
  1346. asCScriptNode *arg = parser.GetScriptNode();
  1347. // Temporarily set the script code to the default arg expression
  1348. asCScriptCode *origScript = script;
  1349. script = &code;
  1350. // Don't allow the expression to access local variables
  1351. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function
  1352. isCompilingDefaultArg = true;
  1353. asSExprContext expr(engine);
  1354. r = CompileExpression(arg, &expr);
  1355. isCompilingDefaultArg = false;
  1356. script = origScript;
  1357. if( r < 0 )
  1358. {
  1359. asCString msg;
  1360. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1361. Error(msg.AddressOf(), node);
  1362. anyErrors = true;
  1363. continue;
  1364. }
  1365. args[n] = asNEW(asSExprContext)(engine);
  1366. MergeExprBytecodeAndType(args[n], &expr);
  1367. // Make sure the default arg expression doesn't end up
  1368. // with a variable that is used in a previous expression
  1369. if( args[n]->type.isVariable )
  1370. {
  1371. int offset = args[n]->type.stackOffset;
  1372. if( varsUsed.Exists(offset) )
  1373. {
  1374. // Release the current temporary variable
  1375. ReleaseTemporaryVariable(args[n]->type, 0);
  1376. asCDataType dt = args[n]->type.dataType;
  1377. dt.MakeReference(false);
  1378. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1379. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1380. args[n]->bc.ExchangeVar(offset, newOffset);
  1381. args[n]->type.stackOffset = (short)newOffset;
  1382. args[n]->type.isTemporary = true;
  1383. args[n]->type.isVariable = true;
  1384. }
  1385. }
  1386. }
  1387. return anyErrors ? -1 : 0;
  1388. }
  1389. 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)
  1390. {
  1391. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1392. asUINT cost = 0;
  1393. asUINT n;
  1394. if( funcs.GetLength() > 0 )
  1395. {
  1396. // Check the number of parameters in the found functions
  1397. for( n = 0; n < funcs.GetLength(); ++n )
  1398. {
  1399. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1400. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1401. {
  1402. bool noMatch = true;
  1403. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1404. {
  1405. // Count the number of default args
  1406. asUINT defaultArgs = 0;
  1407. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1408. if( desc->defaultArgs[d] )
  1409. defaultArgs++;
  1410. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1411. noMatch = false;
  1412. }
  1413. if( noMatch )
  1414. {
  1415. // remove it from the list
  1416. if( n == funcs.GetLength()-1 )
  1417. funcs.PopLast();
  1418. else
  1419. funcs[n] = funcs.PopLast();
  1420. n--;
  1421. }
  1422. }
  1423. }
  1424. // Match functions with the parameters, and discard those that do not match
  1425. asCArray<int> matchingFuncs = funcs;
  1426. for( n = 0; n < args.GetLength(); ++n )
  1427. {
  1428. asCArray<int> tempFuncs;
  1429. cost += MatchArgument(funcs, tempFuncs, &args[n]->type, n, allowObjectConstruct);
  1430. // Intersect the found functions with the list of matching functions
  1431. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1432. {
  1433. asUINT c;
  1434. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1435. {
  1436. if( matchingFuncs[f] == tempFuncs[c] )
  1437. break;
  1438. }
  1439. // Was the function a match?
  1440. if( c == tempFuncs.GetLength() )
  1441. {
  1442. // No, remove it from the list
  1443. if( f == matchingFuncs.GetLength()-1 )
  1444. matchingFuncs.PopLast();
  1445. else
  1446. matchingFuncs[f] = matchingFuncs.PopLast();
  1447. f--;
  1448. }
  1449. }
  1450. }
  1451. funcs = matchingFuncs;
  1452. }
  1453. if( !isConstMethod )
  1454. FilterConst(funcs);
  1455. if( funcs.GetLength() != 1 && !silent )
  1456. {
  1457. // Build a readable string of the function with parameter types
  1458. asCString str;
  1459. if( scope != "" )
  1460. {
  1461. if( scope == "::" )
  1462. str = scope;
  1463. else
  1464. str = scope + "::";
  1465. }
  1466. str += name;
  1467. str += "(";
  1468. if( args.GetLength() )
  1469. str += args[0]->type.dataType.Format();
  1470. for( n = 1; n < args.GetLength(); n++ )
  1471. str += ", " + args[n]->type.dataType.Format();
  1472. str += ")";
  1473. if( isConstMethod )
  1474. str += " const";
  1475. if( objectType && scope == "" )
  1476. str = objectType->name + "::" + str;
  1477. if( funcs.GetLength() == 0 )
  1478. {
  1479. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1480. Error(str.AddressOf(), node);
  1481. // Print the list of candidates
  1482. if( origFuncs.GetLength() > 0 )
  1483. {
  1484. int r = 0, c = 0;
  1485. asASSERT( node );
  1486. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1487. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1488. PrintMatchingFuncs(origFuncs, node);
  1489. }
  1490. }
  1491. else
  1492. {
  1493. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1494. Error(str.AddressOf(), node);
  1495. PrintMatchingFuncs(funcs, node);
  1496. }
  1497. }
  1498. return cost;
  1499. }
  1500. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1501. {
  1502. // Get the data type
  1503. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script);
  1504. // Declare all variables in this declaration
  1505. asCScriptNode *node = decl->firstChild->next;
  1506. while( node )
  1507. {
  1508. // Is the type allowed?
  1509. if( !type.CanBeInstanciated() )
  1510. {
  1511. asCString str;
  1512. // TODO: Change to "'type' cannot be declared as variable"
  1513. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1514. Error(str.AddressOf(), node);
  1515. // Use int instead to avoid further problems
  1516. type = asCDataType::CreatePrimitive(ttInt, false);
  1517. }
  1518. // A shared object may not declare variables of non-shared types
  1519. if( outFunc->objectType && outFunc->objectType->IsShared() )
  1520. {
  1521. asCObjectType *ot = type.GetObjectType();
  1522. if( ot && !ot->IsShared() )
  1523. {
  1524. asCString msg;
  1525. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1526. Error(msg.AddressOf(), decl);
  1527. }
  1528. }
  1529. // Get the name of the identifier
  1530. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1531. // Verify that the name isn't used by a dynamic data type
  1532. if( engine->GetObjectType(name.AddressOf()) != 0 )
  1533. {
  1534. asCString str;
  1535. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1536. Error(str.AddressOf(), node);
  1537. }
  1538. int offset = AllocateVariable(type, false);
  1539. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1540. {
  1541. asCString str;
  1542. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1543. Error(str.AddressOf(), node);
  1544. // Don't continue after this error, as it will just
  1545. // lead to more errors that are likely false
  1546. return;
  1547. }
  1548. // Add marker that the variable has been declared
  1549. bc->VarDecl((int)outFunc->variables.GetLength());
  1550. outFunc->AddVariable(name, type, offset);
  1551. // Keep the node for the variable decl
  1552. asCScriptNode *varNode = node;
  1553. node = node->next;
  1554. if( node && node->nodeType == snArgList )
  1555. {
  1556. // Make sure that it is a registered type, and that is isn't a pointer
  1557. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1558. {
  1559. Error(TXT_MUST_BE_OBJECT, node);
  1560. }
  1561. else
  1562. {
  1563. // Compile the arguments
  1564. asCArray<asSExprContext *> args;
  1565. if( CompileArgumentList(node, args) >= 0 )
  1566. {
  1567. // Find all constructors
  1568. asCArray<int> funcs;
  1569. asSTypeBehaviour *beh = type.GetBehaviour();
  1570. if( beh )
  1571. {
  1572. if( type.GetObjectType()->flags & asOBJ_REF )
  1573. funcs = beh->factories;
  1574. else
  1575. funcs = beh->constructors;
  1576. }
  1577. asCString str = type.Format();
  1578. MatchFunctions(funcs, args, node, str.AddressOf());
  1579. if( funcs.GetLength() == 1 )
  1580. {
  1581. int r = asSUCCESS;
  1582. // Add the default values for arguments not explicitly supplied
  1583. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1584. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1585. r = CompileDefaultArgs(node, args, func);
  1586. if( r == asSUCCESS )
  1587. {
  1588. sVariable *v = variables->GetVariable(name.AddressOf());
  1589. asSExprContext ctx(engine);
  1590. if( v->type.GetObjectType() && (v->type.GetObjectType()->flags & asOBJ_REF) )
  1591. {
  1592. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
  1593. // Pop the reference left by the function call
  1594. ctx.bc.Pop(AS_PTR_SIZE);
  1595. }
  1596. else
  1597. {
  1598. // When the object is allocated on the heap, the address where the
  1599. // reference will be stored must be pushed on the stack before the
  1600. // arguments. This reference on the stack is safe, even if the script
  1601. // is suspended during the evaluation of the arguments.
  1602. if( v->onHeap )
  1603. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1604. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1605. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1606. // When the object is allocated on the stack, the address to the
  1607. // object is pushed on the stack after the arguments as the object pointer
  1608. if( !v->onHeap )
  1609. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1610. PerformFunctionCall(funcs[0], &ctx, v->onHeap, &args, type.GetObjectType());
  1611. // TODO: value on stack: This probably has to be done in PerformFunctionCall
  1612. // Mark the object as initialized
  1613. ctx.bc.ObjInfo(v->stackOffset, asOBJ_INIT);
  1614. }
  1615. bc->AddCode(&ctx.bc);
  1616. }
  1617. }
  1618. }
  1619. // Cleanup
  1620. for( asUINT n = 0; n < args.GetLength(); n++ )
  1621. if( args[n] )
  1622. {
  1623. asDELETE(args[n],asSExprContext);
  1624. }
  1625. }
  1626. node = node->next;
  1627. }
  1628. else if( node && node->nodeType == snInitList )
  1629. {
  1630. sVariable *v = variables->GetVariable(name.AddressOf());
  1631. asCTypeInfo ti;
  1632. ti.Set(type);
  1633. ti.isVariable = true;
  1634. ti.isTemporary = false;
  1635. ti.stackOffset = (short)v->stackOffset;
  1636. ti.isLValue = true;
  1637. CompileInitList(&ti, node, bc);
  1638. node = node->next;
  1639. }
  1640. else if( node && node->nodeType == snAssignment )
  1641. {
  1642. asSExprContext ctx(engine);
  1643. // TODO: copy: Here we should look for the best matching constructor, instead of
  1644. // just the copy constructor. Only if no appropriate constructor is
  1645. // available should the assignment operator be used.
  1646. // Call the default constructor here
  1647. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, varNode);
  1648. // Compile the expression
  1649. asSExprContext expr(engine);
  1650. int r = CompileAssignment(node, &expr);
  1651. if( r >= 0 )
  1652. {
  1653. if( type.IsPrimitive() )
  1654. {
  1655. if( type.IsReadOnly() && expr.type.isConstant )
  1656. {
  1657. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1658. sVariable *v = variables->GetVariable(name.AddressOf());
  1659. v->isPureConstant = true;
  1660. v->constantValue = expr.type.qwordValue;
  1661. }
  1662. asSExprContext lctx(engine);
  1663. lctx.type.SetVariable(type, offset, false);
  1664. lctx.type.dataType.MakeReadOnly(false);
  1665. lctx.type.isLValue = true;
  1666. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1667. ProcessDeferredParams(&ctx);
  1668. }
  1669. else
  1670. {
  1671. // TODO: optimize: We can use a copy constructor here
  1672. sVariable *v = variables->GetVariable(name.AddressOf());
  1673. asSExprContext lexpr(engine);
  1674. lexpr.type.Set(type);
  1675. lexpr.type.dataType.MakeReference(v->onHeap);
  1676. // Allow initialization of constant variables
  1677. lexpr.type.dataType.MakeReadOnly(false);
  1678. if( type.IsObjectHandle() )
  1679. lexpr.type.isExplicitHandle = true;
  1680. lexpr.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1681. lexpr.type.stackOffset = (short)v->stackOffset;
  1682. lexpr.type.isVariable = true;
  1683. lexpr.type.isLValue = true;
  1684. // If left expression resolves into a registered type
  1685. // check if the assignment operator is overloaded, and check
  1686. // the type of the right hand expression. If none is found
  1687. // the default action is a direct copy if it is the same type
  1688. // and a simple assignment.
  1689. bool assigned = false;
  1690. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  1691. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1692. {
  1693. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1694. if( assigned )
  1695. {
  1696. // Pop the resulting value
  1697. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  1698. // Release the argument
  1699. ProcessDeferredParams(&ctx);
  1700. // Release temporary variable that may be allocated by the overloaded operator
  1701. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1702. }
  1703. }
  1704. if( !assigned )
  1705. {
  1706. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  1707. // If the expression is constant and the variable also is constant
  1708. // then mark the variable as pure constant. This will allow the compiler
  1709. // to optimize expressions with this variable.
  1710. if( v->type.IsReadOnly() && expr.type.isConstant )
  1711. {
  1712. v->isPureConstant = true;
  1713. v->constantValue = expr.type.qwordValue;
  1714. }
  1715. // Add expression code to bytecode
  1716. MergeExprBytecode(&ctx, &expr);
  1717. // Add byte code for storing value of expression in variable
  1718. ctx.bc.AddCode(&lexpr.bc);
  1719. lexpr.type.stackOffset = (short)v->stackOffset;
  1720. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node->prev);
  1721. // Release temporary variables used by expression
  1722. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  1723. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  1724. ProcessDeferredParams(&ctx);
  1725. }
  1726. }
  1727. }
  1728. node = node->next;
  1729. bc->AddCode(&ctx.bc);
  1730. // TODO: Can't this leave deferred output params without being compiled?
  1731. }
  1732. else
  1733. {
  1734. // Call the default constructor here if no explicit initialization is done
  1735. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, varNode);
  1736. }
  1737. }
  1738. }
  1739. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc)
  1740. {
  1741. // Check if the type supports initialization lists
  1742. if( var->dataType.GetObjectType() == 0 ||
  1743. var->dataType.GetBehaviour()->listFactory == 0 ||
  1744. var->dataType.IsObjectHandle() )
  1745. {
  1746. asCString str;
  1747. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  1748. Error(str.AddressOf(), node);
  1749. return;
  1750. }
  1751. // Count the number of elements and initialize the array with the correct size
  1752. int countElements = 0;
  1753. asCScriptNode *el = node->firstChild;
  1754. while( el )
  1755. {
  1756. countElements++;
  1757. el = el->next;
  1758. }
  1759. // Construct the array with the size elements
  1760. // TODO: value on stack: This needs to support value types on the stack as well
  1761. // Find the list factory
  1762. // TODO: initlist: Add support for value types as well
  1763. int funcId = var->dataType.GetBehaviour()->listFactory;
  1764. asCArray<asSExprContext *> args;
  1765. asSExprContext arg1(engine);
  1766. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  1767. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  1768. args.PushLast(&arg1);
  1769. asSExprContext ctx(engine);
  1770. PrepareFunctionCall(funcId, &ctx.bc, args);
  1771. MoveArgsToStack(funcId, &ctx.bc, args, false);
  1772. if( var->isVariable )
  1773. {
  1774. // Call factory and store the handle in the given variable
  1775. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  1776. ctx.bc.Pop(AS_PTR_SIZE);
  1777. }
  1778. else
  1779. {
  1780. PerformFunctionCall(funcId, &ctx, false, &args);
  1781. // Store the returned handle in the global variable
  1782. ctx.bc.Instr(asBC_RDSPTR);
  1783. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1784. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  1785. ctx.bc.Pop(AS_PTR_SIZE);
  1786. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1787. }
  1788. bc->AddCode(&ctx.bc);
  1789. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  1790. // initialization lists with different types for different elements? Maybe
  1791. // by using the variable arguments the initialization can be done with one
  1792. // call, passing all the elements as arguments. The registered function can
  1793. // then traverse them however it wants.
  1794. // Find the indexing operator that is not read-only that will be used for all elements
  1795. asCDataType retType;
  1796. retType = var->dataType.GetSubType();
  1797. retType.MakeReference(true);
  1798. retType.MakeReadOnly(false);
  1799. funcId = 0;
  1800. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  1801. {
  1802. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  1803. if( !desc->isReadOnly &&
  1804. desc->parameterTypes.GetLength() == 1 &&
  1805. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1806. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1807. desc->returnType == retType &&
  1808. desc->name == "opIndex" )
  1809. {
  1810. funcId = var->dataType.GetObjectType()->methods[n];
  1811. break;
  1812. }
  1813. }
  1814. if( funcId == 0 )
  1815. {
  1816. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  1817. return;
  1818. }
  1819. asUINT index = 0;
  1820. el = node->firstChild;
  1821. while( el )
  1822. {
  1823. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  1824. {
  1825. asSExprContext lctx(engine);
  1826. asSExprContext rctx(engine);
  1827. if( el->nodeType == snAssignment )
  1828. {
  1829. // Compile the assignment expression
  1830. CompileAssignment(el, &rctx);
  1831. }
  1832. else if( el->nodeType == snInitList )
  1833. {
  1834. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  1835. rctx.type.Set(var->dataType.GetSubType());
  1836. rctx.type.isVariable = true;
  1837. rctx.type.isTemporary = true;
  1838. rctx.type.stackOffset = (short)offset;
  1839. CompileInitList(&rctx.type, el, &rctx.bc);
  1840. // Put the object on the stack
  1841. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  1842. // It is a reference that we place on the stack
  1843. rctx.type.dataType.MakeReference(true);
  1844. }
  1845. // Compile the lvalue
  1846. lctx.bc.InstrDWORD(asBC_PshC4, index);
  1847. if( var->isVariable )
  1848. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  1849. else
  1850. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1851. lctx.bc.Instr(asBC_RDSPTR);
  1852. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  1853. if( !var->dataType.GetSubType().IsPrimitive() )
  1854. lctx.bc.Instr(asBC_PshRPtr);
  1855. lctx.type.Set(var->dataType.GetSubType());
  1856. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  1857. lctx.type.dataType.MakeReference(true);
  1858. // If the element type is handles, then we're expected to do handle assignments
  1859. if( lctx.type.dataType.IsObjectHandle() )
  1860. lctx.type.isExplicitHandle = true;
  1861. lctx.type.isLValue = true;
  1862. asSExprContext ctx(engine);
  1863. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  1864. if( !lctx.type.dataType.IsPrimitive() )
  1865. ctx.bc.Pop(AS_PTR_SIZE);
  1866. // Release temporary variables used by expression
  1867. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1868. ProcessDeferredParams(&ctx);
  1869. bc->AddCode(&ctx.bc);
  1870. }
  1871. el = el->next;
  1872. index++;
  1873. }
  1874. }
  1875. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  1876. {
  1877. *hasReturn = false;
  1878. if( statement->nodeType == snStatementBlock )
  1879. CompileStatementBlock(statement, true, hasReturn, bc);
  1880. else if( statement->nodeType == snIf )
  1881. CompileIfStatement(statement, hasReturn, bc);
  1882. else if( statement->nodeType == snFor )
  1883. CompileForStatement(statement, bc);
  1884. else if( statement->nodeType == snWhile )
  1885. CompileWhileStatement(statement, bc);
  1886. else if( statement->nodeType == snDoWhile )
  1887. CompileDoWhileStatement(statement, bc);
  1888. else if( statement->nodeType == snExpressionStatement )
  1889. CompileExpressionStatement(statement, bc);
  1890. else if( statement->nodeType == snBreak )
  1891. CompileBreakStatement(statement, bc);
  1892. else if( statement->nodeType == snContinue )
  1893. CompileContinueStatement(statement, bc);
  1894. else if( statement->nodeType == snSwitch )
  1895. CompileSwitchStatement(statement, hasReturn, bc);
  1896. else if( statement->nodeType == snReturn )
  1897. {
  1898. CompileReturnStatement(statement, bc);
  1899. *hasReturn = true;
  1900. }
  1901. }
  1902. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  1903. {
  1904. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  1905. // Reserve label for break statements
  1906. int breakLabel = nextLabel++;
  1907. breakLabels.PushLast(breakLabel);
  1908. // Add a variable scope that will be used by CompileBreak
  1909. // to know where to stop deallocating variables
  1910. AddVariableScope(true, false);
  1911. //---------------------------
  1912. // Compile the switch expression
  1913. //-------------------------------
  1914. // Compile the switch expression
  1915. asSExprContext expr(engine);
  1916. CompileAssignment(snode->firstChild, &expr);
  1917. // Verify that the expression is a primitive type
  1918. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
  1919. {
  1920. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  1921. return;
  1922. }
  1923. ProcessPropertyGetAccessor(&expr, snode);
  1924. // TODO: Need to support 64bit integers
  1925. // Convert the expression to a 32bit variable
  1926. asCDataType to;
  1927. if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
  1928. to.SetTokenType(ttInt);
  1929. else if( expr.type.dataType.IsUnsignedType() )
  1930. to.SetTokenType(ttUInt);
  1931. // Make sure the value is in a variable
  1932. if( expr.type.dataType.IsReference() )
  1933. ConvertToVariable(&expr);
  1934. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  1935. ConvertToVariable(&expr);
  1936. int offset = expr.type.stackOffset;
  1937. ProcessDeferredParams(&expr);
  1938. //-------------------------------
  1939. // Determine case values and labels
  1940. //--------------------------------
  1941. // Remember the first label so that we can later pass the
  1942. // correct label to each CompileCase()
  1943. int firstCaseLabel = nextLabel;
  1944. int defaultLabel = 0;
  1945. asCArray<int> caseValues;
  1946. asCArray<int> caseLabels;
  1947. // Compile all case comparisons and make them jump to the right label
  1948. asCScriptNode *cnode = snode->firstChild->next;
  1949. while( cnode )
  1950. {
  1951. // Each case should have a constant expression
  1952. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1953. {
  1954. // Compile expression
  1955. asSExprContext c(engine);
  1956. CompileExpression(cnode->firstChild, &c);
  1957. // Verify that the result is a constant
  1958. if( !c.type.isConstant )
  1959. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  1960. // Verify that the result is an integral number
  1961. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
  1962. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  1963. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  1964. // Has this case been declared already?
  1965. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  1966. {
  1967. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  1968. }
  1969. // TODO: Optimize: We can insert the numbers sorted already
  1970. // Store constant for later use
  1971. caseValues.PushLast(c.type.intValue);
  1972. // Reserve label for this case
  1973. caseLabels.PushLast(nextLabel++);
  1974. }
  1975. else
  1976. {
  1977. // Is default the last case?
  1978. if( cnode->next )
  1979. {
  1980. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  1981. break;
  1982. }
  1983. // Reserve label for this case
  1984. defaultLabel = nextLabel++;
  1985. }
  1986. cnode = cnode->next;
  1987. }
  1988. // check for empty switch
  1989. if (caseValues.GetLength() == 0)
  1990. {
  1991. Error(TXT_EMPTY_SWITCH, snode);
  1992. return;
  1993. }
  1994. if( defaultLabel == 0 )
  1995. defaultLabel = breakLabel;
  1996. //---------------------------------
  1997. // Output the optimized case comparisons
  1998. // with jumps to the case code
  1999. //------------------------------------
  2000. // Sort the case values by increasing value. Do the sort together with the labels
  2001. // A simple bubble sort is sufficient since we don't expect a huge number of values
  2002. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  2003. {
  2004. for( int bck = fwd - 1; bck >= 0; bck-- )
  2005. {
  2006. int bckp = bck + 1;
  2007. if( caseValues[bck] > caseValues[bckp] )
  2008. {
  2009. // Swap the values in both arrays
  2010. int swap = caseValues[bckp];
  2011. caseValues[bckp] = caseValues[bck];
  2012. caseValues[bck] = swap;
  2013. swap = caseLabels[bckp];
  2014. caseLabels[bckp] = caseLabels[bck];
  2015. caseLabels[bck] = swap;
  2016. }
  2017. else
  2018. break;
  2019. }
  2020. }
  2021. // Find ranges of consecutive numbers
  2022. asCArray<int> ranges;
  2023. ranges.PushLast(0);
  2024. asUINT n;
  2025. for( n = 1; n < caseValues.GetLength(); ++n )
  2026. {
  2027. // We can join numbers that are less than 5 numbers
  2028. // apart since the output code will still be smaller
  2029. if( caseValues[n] > caseValues[n-1] + 5 )
  2030. ranges.PushLast(n);
  2031. }
  2032. // If the value is larger than the largest case value, jump to default
  2033. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2034. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  2035. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2036. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  2037. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2038. // TODO: optimize: We could possibly optimize this even more by doing a
  2039. // binary search instead of a linear search through the ranges
  2040. // For each range
  2041. int range;
  2042. for( range = 0; range < (int)ranges.GetLength(); range++ )
  2043. {
  2044. // Find the largest value in this range
  2045. int maxRange = caseValues[ranges[range]];
  2046. int index = ranges[range];
  2047. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  2048. maxRange = caseValues[index];
  2049. // If there are only 2 numbers then it is better to compare them directly
  2050. if( index - ranges[range] > 2 )
  2051. {
  2052. // If the value is smaller than the smallest case value in the range, jump to default
  2053. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2054. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2055. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2056. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  2057. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2058. int nextRangeLabel = nextLabel++;
  2059. // If this is the last range we don't have to make this test
  2060. if( range < (int)ranges.GetLength() - 1 )
  2061. {
  2062. // If the value is larger than the largest case value in the range, jump to the next range
  2063. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2064. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  2065. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2066. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  2067. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2068. }
  2069. // Jump forward according to the value
  2070. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2071. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2072. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  2073. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2074. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  2075. // Add the list of jumps to the correct labels (any holes, jump to default)
  2076. index = ranges[range];
  2077. for( int n = caseValues[index]; n <= maxRange; n++ )
  2078. {
  2079. if( caseValues[index] == n )
  2080. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  2081. else
  2082. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2083. }
  2084. expr.bc.Label((short)nextRangeLabel);
  2085. }
  2086. else
  2087. {
  2088. // Simply make a comparison with each value
  2089. int n;
  2090. for( n = ranges[range]; n < index; ++n )
  2091. {
  2092. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2093. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  2094. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2095. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2096. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2097. }
  2098. }
  2099. }
  2100. // Catch any value that falls trough
  2101. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2102. // Release the temporary variable previously stored
  2103. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2104. //----------------------------------
  2105. // Output case implementations
  2106. //----------------------------------
  2107. // Compile case implementations, each one with the label before it
  2108. cnode = snode->firstChild->next;
  2109. while( cnode )
  2110. {
  2111. // Each case should have a constant expression
  2112. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2113. {
  2114. expr.bc.Label((short)firstCaseLabel++);
  2115. CompileCase(cnode->firstChild->next, &expr.bc);
  2116. }
  2117. else
  2118. {
  2119. expr.bc.Label((short)defaultLabel);
  2120. // Is default the last case?
  2121. if( cnode->next )
  2122. {
  2123. // We've already reported this error
  2124. break;
  2125. }
  2126. CompileCase(cnode->firstChild, &expr.bc);
  2127. }
  2128. cnode = cnode->next;
  2129. }
  2130. //--------------------------------
  2131. bc->AddCode(&expr.bc);
  2132. // Add break label
  2133. bc->Label((short)breakLabel);
  2134. breakLabels.PopLast();
  2135. RemoveVariableScope();
  2136. }
  2137. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2138. {
  2139. bool isFinished = false;
  2140. bool hasReturn = false;
  2141. while( node )
  2142. {
  2143. if( hasReturn || isFinished )
  2144. {
  2145. Warning(TXT_UNREACHABLE_CODE, node);
  2146. break;
  2147. }
  2148. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2149. isFinished = true;
  2150. asCByteCode statement(engine);
  2151. if( node->nodeType == snDeclaration )
  2152. {
  2153. Error(TXT_DECL_IN_SWITCH, node);
  2154. // Compile it anyway to avoid further compiler errors
  2155. CompileDeclaration(node, &statement);
  2156. }
  2157. else
  2158. CompileStatement(node, &hasReturn, &statement);
  2159. LineInstr(bc, node->tokenPos);
  2160. bc->AddCode(&statement);
  2161. if( !hasCompileErrors )
  2162. asASSERT( tempVariables.GetLength() == 0 );
  2163. node = node->next;
  2164. }
  2165. }
  2166. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2167. {
  2168. // We will use one label for the if statement
  2169. // and possibly another for the else statement
  2170. int afterLabel = nextLabel++;
  2171. // Compile the expression
  2172. asSExprContext expr(engine);
  2173. CompileAssignment(inode->firstChild, &expr);
  2174. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2175. {
  2176. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2177. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2178. }
  2179. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2180. ProcessDeferredParams(&expr);
  2181. if( !expr.type.isConstant )
  2182. {
  2183. ProcessPropertyGetAccessor(&expr, inode);
  2184. ConvertToVariable(&expr);
  2185. // Add byte code from the expression
  2186. bc->AddCode(&expr.bc);
  2187. // Add a test
  2188. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2189. bc->Instr(asBC_ClrHi);
  2190. bc->InstrDWORD(asBC_JZ, afterLabel);
  2191. ReleaseTemporaryVariable(expr.type, bc);
  2192. }
  2193. else if( expr.type.dwordValue == 0 )
  2194. {
  2195. // Jump to the else case
  2196. bc->InstrINT(asBC_JMP, afterLabel);
  2197. // TODO: Should we warn that the expression will always go to the else?
  2198. }
  2199. // Compile the if statement
  2200. bool origIsConstructorCalled = m_isConstructorCalled;
  2201. bool hasReturn1;
  2202. asCByteCode ifBC(engine);
  2203. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2204. // Add the byte code
  2205. LineInstr(bc, inode->firstChild->next->tokenPos);
  2206. bc->AddCode(&ifBC);
  2207. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2208. {
  2209. // Don't allow if( expr );
  2210. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2211. }
  2212. // If one of the statements call the constructor, the other must as well
  2213. // otherwise it is possible the constructor is never called
  2214. bool constructorCall1 = false;
  2215. bool constructorCall2 = false;
  2216. if( !origIsConstructorCalled && m_isConstructorCalled )
  2217. constructorCall1 = true;
  2218. // Do we have an else statement?
  2219. if( inode->firstChild->next != inode->lastChild )
  2220. {
  2221. // Reset the constructor called flag so the else statement can call the constructor too
  2222. m_isConstructorCalled = origIsConstructorCalled;
  2223. int afterElse = 0;
  2224. if( !hasReturn1 )
  2225. {
  2226. afterElse = nextLabel++;
  2227. // Add jump to after the else statement
  2228. bc->InstrINT(asBC_JMP, afterElse);
  2229. }
  2230. // Add label for the else statement
  2231. bc->Label((short)afterLabel);
  2232. bool hasReturn2;
  2233. asCByteCode elseBC(engine);
  2234. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2235. // Add byte code for the else statement
  2236. LineInstr(bc, inode->lastChild->tokenPos);
  2237. bc->AddCode(&elseBC);
  2238. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2239. {
  2240. // Don't allow if( expr ) {} else;
  2241. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2242. }
  2243. if( !hasReturn1 )
  2244. {
  2245. // Add label for the end of else statement
  2246. bc->Label((short)afterElse);
  2247. }
  2248. // The if statement only has return if both alternatives have
  2249. *hasReturn = hasReturn1 && hasReturn2;
  2250. if( !origIsConstructorCalled && m_isConstructorCalled )
  2251. constructorCall2 = true;
  2252. }
  2253. else
  2254. {
  2255. // Add label for the end of if statement
  2256. bc->Label((short)afterLabel);
  2257. *hasReturn = false;
  2258. }
  2259. // Make sure both or neither conditions call a constructor
  2260. if( (constructorCall1 && !constructorCall2) ||
  2261. (constructorCall2 && !constructorCall1) )
  2262. {
  2263. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2264. }
  2265. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2266. }
  2267. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2268. {
  2269. // TODO: optimize: We should be able to remove the static JMP to the beginning of the loop by rearranging the
  2270. // byte code a bit.
  2271. //
  2272. // init
  2273. // jump to before
  2274. // begin:
  2275. // statements
  2276. // continue:
  2277. // next
  2278. // before:
  2279. // condition
  2280. // if loop jump to begin
  2281. // break:
  2282. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2283. AddVariableScope(true, true);
  2284. // We will use three labels for the for loop
  2285. int beforeLabel = nextLabel++;
  2286. int afterLabel = nextLabel++;
  2287. int continueLabel = nextLabel++;
  2288. continueLabels.PushLast(continueLabel);
  2289. breakLabels.PushLast(afterLabel);
  2290. //---------------------------------------
  2291. // Compile the initialization statement
  2292. asCByteCode initBC(engine);
  2293. if( fnode->firstChild->nodeType == snDeclaration )
  2294. CompileDeclaration(fnode->firstChild, &initBC);
  2295. else
  2296. CompileExpressionStatement(fnode->firstChild, &initBC);
  2297. //-----------------------------------
  2298. // Compile the condition statement
  2299. asSExprContext expr(engine);
  2300. asCScriptNode *second = fnode->firstChild->next;
  2301. if( second->firstChild )
  2302. {
  2303. int r = CompileAssignment(second->firstChild, &expr);
  2304. if( r >= 0 )
  2305. {
  2306. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2307. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2308. else
  2309. {
  2310. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2311. ProcessDeferredParams(&expr);
  2312. ProcessPropertyGetAccessor(&expr, second);
  2313. // If expression is false exit the loop
  2314. ConvertToVariable(&expr);
  2315. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2316. expr.bc.Instr(asBC_ClrHi);
  2317. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2318. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2319. }
  2320. }
  2321. }
  2322. //---------------------------
  2323. // Compile the increment statement
  2324. asCByteCode nextBC(engine);
  2325. asCScriptNode *third = second->next;
  2326. if( third->nodeType == snExpressionStatement )
  2327. CompileExpressionStatement(third, &nextBC);
  2328. //------------------------------
  2329. // Compile loop statement
  2330. bool hasReturn;
  2331. asCByteCode forBC(engine);
  2332. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2333. //-------------------------------
  2334. // Join the code pieces
  2335. bc->AddCode(&initBC);
  2336. bc->Label((short)beforeLabel);
  2337. // Add a suspend bytecode inside the loop to guarantee
  2338. // that the application can suspend the execution
  2339. bc->Instr(asBC_SUSPEND);
  2340. bc->InstrPTR(asBC_JitEntry, 0);
  2341. bc->AddCode(&expr.bc);
  2342. LineInstr(bc, fnode->lastChild->tokenPos);
  2343. bc->AddCode(&forBC);
  2344. bc->Label((short)continueLabel);
  2345. bc->AddCode(&nextBC);
  2346. bc->InstrINT(asBC_JMP, beforeLabel);
  2347. bc->Label((short)afterLabel);
  2348. continueLabels.PopLast();
  2349. breakLabels.PopLast();
  2350. // Deallocate variables in this block, in reverse order
  2351. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2352. {
  2353. sVariable *v = variables->variables[n];
  2354. // Call variable destructors here, for variables not yet destroyed
  2355. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2356. // Don't deallocate function parameters
  2357. if( v->stackOffset > 0 )
  2358. DeallocateVariable(v->stackOffset);
  2359. }
  2360. RemoveVariableScope();
  2361. }
  2362. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2363. {
  2364. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2365. AddVariableScope(true, true);
  2366. // We will use two labels for the while loop
  2367. int beforeLabel = nextLabel++;
  2368. int afterLabel = nextLabel++;
  2369. continueLabels.PushLast(beforeLabel);
  2370. breakLabels.PushLast(afterLabel);
  2371. // Add label before the expression
  2372. bc->Label((short)beforeLabel);
  2373. // Compile expression
  2374. asSExprContext expr(engine);
  2375. CompileAssignment(wnode->firstChild, &expr);
  2376. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2377. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2378. else
  2379. {
  2380. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2381. ProcessDeferredParams(&expr);
  2382. ProcessPropertyGetAccessor(&expr, wnode);
  2383. // Add byte code for the expression
  2384. ConvertToVariable(&expr);
  2385. bc->AddCode(&expr.bc);
  2386. // Jump to end of statement if expression is false
  2387. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2388. bc->Instr(asBC_ClrHi);
  2389. bc->InstrDWORD(asBC_JZ, afterLabel);
  2390. ReleaseTemporaryVariable(expr.type, bc);
  2391. }
  2392. // Add a suspend bytecode inside the loop to guarantee
  2393. // that the application can suspend the execution
  2394. bc->Instr(asBC_SUSPEND);
  2395. bc->InstrPTR(asBC_JitEntry, 0);
  2396. // Compile statement
  2397. bool hasReturn;
  2398. asCByteCode whileBC(engine);
  2399. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2400. // Add byte code for the statement
  2401. LineInstr(bc, wnode->lastChild->tokenPos);
  2402. bc->AddCode(&whileBC);
  2403. // Jump to the expression
  2404. bc->InstrINT(asBC_JMP, beforeLabel);
  2405. // Add label after the statement
  2406. bc->Label((short)afterLabel);
  2407. continueLabels.PopLast();
  2408. breakLabels.PopLast();
  2409. RemoveVariableScope();
  2410. }
  2411. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2412. {
  2413. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2414. AddVariableScope(true, true);
  2415. // We will use two labels for the while loop
  2416. int beforeLabel = nextLabel++;
  2417. int beforeTest = nextLabel++;
  2418. int afterLabel = nextLabel++;
  2419. continueLabels.PushLast(beforeTest);
  2420. breakLabels.PushLast(afterLabel);
  2421. // Add label before the statement
  2422. bc->Label((short)beforeLabel);
  2423. // Compile statement
  2424. bool hasReturn;
  2425. asCByteCode whileBC(engine);
  2426. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2427. // Add byte code for the statement
  2428. LineInstr(bc, wnode->firstChild->tokenPos);
  2429. bc->AddCode(&whileBC);
  2430. // Add label before the expression
  2431. bc->Label((short)beforeTest);
  2432. // Add a suspend bytecode inside the loop to guarantee
  2433. // that the application can suspend the execution
  2434. bc->Instr(asBC_SUSPEND);
  2435. bc->InstrPTR(asBC_JitEntry, 0);
  2436. // Add a line instruction
  2437. LineInstr(bc, wnode->lastChild->tokenPos);
  2438. // Compile expression
  2439. asSExprContext expr(engine);
  2440. CompileAssignment(wnode->lastChild, &expr);
  2441. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2442. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2443. else
  2444. {
  2445. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2446. ProcessDeferredParams(&expr);
  2447. ProcessPropertyGetAccessor(&expr, wnode);
  2448. // Add byte code for the expression
  2449. ConvertToVariable(&expr);
  2450. bc->AddCode(&expr.bc);
  2451. // Jump to next iteration if expression is true
  2452. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2453. bc->Instr(asBC_ClrHi);
  2454. bc->InstrDWORD(asBC_JNZ, beforeLabel);
  2455. ReleaseTemporaryVariable(expr.type, bc);
  2456. }
  2457. // Add label after the statement
  2458. bc->Label((short)afterLabel);
  2459. continueLabels.PopLast();
  2460. breakLabels.PopLast();
  2461. RemoveVariableScope();
  2462. }
  2463. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2464. {
  2465. if( breakLabels.GetLength() == 0 )
  2466. {
  2467. Error(TXT_INVALID_BREAK, node);
  2468. return;
  2469. }
  2470. // Add destructor calls for all variables that will go out of scope
  2471. // Put this clean up in a block to allow exception handler to understand them
  2472. bc->Block(true);
  2473. asCVariableScope *vs = variables;
  2474. while( !vs->isBreakScope )
  2475. {
  2476. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2477. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2478. vs = vs->parent;
  2479. }
  2480. bc->Block(false);
  2481. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2482. }
  2483. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2484. {
  2485. if( continueLabels.GetLength() == 0 )
  2486. {
  2487. Error(TXT_INVALID_CONTINUE, node);
  2488. return;
  2489. }
  2490. // Add destructor calls for all variables that will go out of scope
  2491. // Put this clean up in a block to allow exception handler to understand them
  2492. bc->Block(true);
  2493. asCVariableScope *vs = variables;
  2494. while( !vs->isContinueScope )
  2495. {
  2496. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2497. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2498. vs = vs->parent;
  2499. }
  2500. bc->Block(false);
  2501. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2502. }
  2503. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2504. {
  2505. if( enode->firstChild )
  2506. {
  2507. // Compile the expression
  2508. asSExprContext expr(engine);
  2509. CompileAssignment(enode->firstChild, &expr);
  2510. // Pop the value from the stack
  2511. if( !expr.type.dataType.IsPrimitive() )
  2512. expr.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  2513. // Release temporary variables used by expression
  2514. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2515. ProcessDeferredParams(&expr);
  2516. bc->AddCode(&expr.bc);
  2517. }
  2518. }
  2519. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  2520. {
  2521. // If the object already is stored in temporary variable then nothing needs to be done
  2522. // Note, a type can be temporary without being a variable, in which case it is holding off
  2523. // on releasing a previously used object.
  2524. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2525. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2526. {
  2527. // If the temporary object is currently not a reference
  2528. // the expression needs to be reevaluated to a reference
  2529. if( !ctx->type.dataType.IsReference() )
  2530. {
  2531. ctx->bc.Pop(AS_PTR_SIZE);
  2532. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2533. ctx->type.dataType.MakeReference(true);
  2534. }
  2535. return;
  2536. }
  2537. // Allocate temporary variable
  2538. asCDataType dt = ctx->type.dataType;
  2539. dt.MakeReference(false);
  2540. dt.MakeReadOnly(false);
  2541. int offset = AllocateVariable(dt, true, forceOnHeap);
  2542. // Objects stored on the stack are not considered references
  2543. dt.MakeReference(IsVariableOnHeap(offset));
  2544. asCTypeInfo lvalue;
  2545. lvalue.Set(dt);
  2546. lvalue.isTemporary = true;
  2547. lvalue.stackOffset = (short)offset;
  2548. lvalue.isVariable = true;
  2549. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2550. if( !dt.IsObjectHandle() &&
  2551. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2552. {
  2553. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2554. // Use the copy constructor/factory when available
  2555. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2556. }
  2557. else
  2558. {
  2559. // Allocate and construct the temporary object
  2560. int r = CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2561. if( r < 0 )
  2562. {
  2563. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2564. }
  2565. else
  2566. {
  2567. // Assign the object to the temporary variable
  2568. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2569. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2570. r = PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2571. if( r < 0 )
  2572. {
  2573. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2574. }
  2575. // Pop the original reference
  2576. ctx->bc.Pop(AS_PTR_SIZE);
  2577. }
  2578. }
  2579. // If the expression was holding off on releasing a
  2580. // previously used object, we need to release it now
  2581. if( ctx->type.isTemporary )
  2582. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2583. // Push the reference to the temporary variable on the stack
  2584. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2585. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2586. ctx->type = lvalue;
  2587. }
  2588. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2589. {
  2590. // Get return type and location
  2591. sVariable *v = variables->GetVariable("return");
  2592. // Basic validations
  2593. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2594. {
  2595. Error(TXT_MUST_RETURN_VALUE, rnode);
  2596. return;
  2597. }
  2598. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2599. {
  2600. Error(TXT_CANT_RETURN_VALUE, rnode);
  2601. return;
  2602. }
  2603. // Compile the expression
  2604. if( rnode->firstChild )
  2605. {
  2606. // Compile the expression
  2607. asSExprContext expr(engine);
  2608. int r = CompileAssignment(rnode->firstChild, &expr);
  2609. if( r < 0 ) return;
  2610. if( v->type.IsReference() )
  2611. {
  2612. // The expression that gives the reference must not use any of the
  2613. // variables that must be destroyed upon exit, because then it means
  2614. // reference will stay alive while the clean-up is done, which could
  2615. // potentially mean that the reference is invalidated by the clean-up.
  2616. //
  2617. // When the function is returning a reference, the clean-up of the
  2618. // variables must be done before the evaluation of the expression.
  2619. //
  2620. // A reference to a global variable, or a class member for class methods
  2621. // should be allowed to be returned.
  2622. if( !(expr.type.dataType.IsReference() ||
  2623. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2624. {
  2625. // Clean up the potential deferred parameters
  2626. ProcessDeferredParams(&expr);
  2627. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2628. return;
  2629. }
  2630. // No references to local variables, temporary variables, or parameters
  2631. // are allowed to be returned, since they go out of scope when the function
  2632. // returns. Even reference parameters are disallowed, since it is not possible
  2633. // to know the scope of them. The exception is the 'this' pointer, which
  2634. // is treated by the compiler as a local variable, but isn't really so.
  2635. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2636. {
  2637. // Clean up the potential deferred parameters
  2638. ProcessDeferredParams(&expr);
  2639. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2640. return;
  2641. }
  2642. // The type must match exactly as we cannot convert
  2643. // the reference without loosing the original value
  2644. if( !(v->type == expr.type.dataType ||
  2645. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRef(expr.type.dataType))) )
  2646. {
  2647. // Clean up the potential deferred parameters
  2648. ProcessDeferredParams(&expr);
  2649. asCString str;
  2650. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2651. Error(str.AddressOf(), rnode);
  2652. return;
  2653. }
  2654. // The expression must not have any deferred expressions, because the evaluation
  2655. // of these cannot be done without keeping the reference which is not safe
  2656. if( expr.deferredParams.GetLength() )
  2657. {
  2658. // Clean up the potential deferred parameters
  2659. ProcessDeferredParams(&expr);
  2660. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2661. return;
  2662. }
  2663. // Make sure the expression isn't using any local variables that
  2664. // will need to be cleaned up before the function completes
  2665. asCArray<int> usedVars;
  2666. expr.bc.GetVarsUsed(usedVars);
  2667. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  2668. {
  2669. int var = GetVariableSlot(usedVars[n]);
  2670. if( var != -1 )
  2671. {
  2672. asCDataType dt = variableAllocations[var];
  2673. if( dt.IsObject() )
  2674. {
  2675. ProcessDeferredParams(&expr);
  2676. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  2677. return;
  2678. }
  2679. }
  2680. }
  2681. // All objects in the function must be cleaned up before the expression
  2682. // is evaluated, otherwise there is a possibility that the cleanup will
  2683. // invalidate the reference.
  2684. // Destroy the local variables before loading
  2685. // the reference into the register. This will
  2686. // be done before the expression is evaluated.
  2687. DestroyVariables(bc);
  2688. // For primitives the reference is already in the register,
  2689. // but for non-primitives the reference is on the stack so we
  2690. // need to load it into the register
  2691. if( !expr.type.dataType.IsPrimitive() )
  2692. {
  2693. if( !expr.type.dataType.IsObjectHandle() &&
  2694. expr.type.dataType.IsReference() )
  2695. expr.bc.Instr(asBC_RDSPTR);
  2696. expr.bc.Instr(asBC_PopRPtr);
  2697. }
  2698. // There are no temporaries to release so we're done
  2699. }
  2700. else // if( !v->type.IsReference() )
  2701. {
  2702. ProcessPropertyGetAccessor(&expr, rnode);
  2703. // Prepare the value for assignment
  2704. IsVariableInitialized(&expr.type, rnode->firstChild);
  2705. if( v->type.IsPrimitive() )
  2706. {
  2707. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2708. // Implicitly convert the value to the return type
  2709. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2710. // Verify that the conversion was successful
  2711. if( expr.type.dataType != v->type )
  2712. {
  2713. asCString str;
  2714. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2715. Error(str.AddressOf(), rnode);
  2716. return;
  2717. }
  2718. else
  2719. {
  2720. ConvertToVariable(&expr);
  2721. // Clean up the local variables and process deferred parameters
  2722. DestroyVariables(&expr.bc);
  2723. ProcessDeferredParams(&expr);
  2724. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2725. // Load the variable in the register
  2726. if( v->type.GetSizeOnStackDWords() == 1 )
  2727. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2728. else
  2729. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  2730. }
  2731. }
  2732. else if( v->type.IsObject() )
  2733. {
  2734. #ifndef AS_OLD
  2735. // Value types are returned on the stack, in a location
  2736. // that has been reserved by the calling function.
  2737. if( outFunc->DoesReturnOnStack() )
  2738. {
  2739. // TODO: optimize: If the return type has a constructor that takes the type of the expression,
  2740. // it should be called directly instead of first converting the expression and
  2741. // then copy the value.
  2742. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2743. {
  2744. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2745. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  2746. {
  2747. asCString str;
  2748. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2749. Error(str.AddressOf(), rnode->firstChild);
  2750. return;
  2751. }
  2752. }
  2753. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  2754. if( v->type.GetObjectType()->beh.copyconstruct )
  2755. {
  2756. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  2757. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  2758. }
  2759. else
  2760. {
  2761. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  2762. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, false, true);
  2763. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  2764. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2765. expr.bc.Instr(asBC_RDSPTR);
  2766. asSExprContext lexpr(engine);
  2767. lexpr.type.Set(v->type);
  2768. lexpr.type.isLValue = true;
  2769. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  2770. expr.bc.Pop(AS_PTR_SIZE);
  2771. // Release any temporary variable
  2772. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2773. }
  2774. // Clean up the local variables and process deferred parameters
  2775. DestroyVariables(&expr.bc);
  2776. ProcessDeferredParams(&expr);
  2777. }
  2778. else
  2779. #endif
  2780. {
  2781. #ifndef AS_OLD
  2782. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  2783. #endif
  2784. // Prepare the expression to be loaded into the object
  2785. // register. This will place the reference in local variable
  2786. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  2787. // Pop the reference to the temporary variable
  2788. expr.bc.Pop(AS_PTR_SIZE);
  2789. // Clean up the local variables and process deferred parameters
  2790. DestroyVariables(&expr.bc);
  2791. ProcessDeferredParams(&expr);
  2792. // Load the object pointer into the object register
  2793. // LOADOBJ also clears the address in the variable
  2794. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  2795. // LOADOBJ cleared the address in the variable so the object will not be freed
  2796. // here, but the temporary variable must still be freed so the slot can be reused
  2797. // By releasing without the bytecode we do just that.
  2798. ReleaseTemporaryVariable(expr.type, 0);
  2799. }
  2800. }
  2801. }
  2802. bc->AddCode(&expr.bc);
  2803. }
  2804. else
  2805. {
  2806. // For functions that don't return anything
  2807. // we just detroy the local variables
  2808. DestroyVariables(bc);
  2809. }
  2810. // Jump to the end of the function
  2811. bc->InstrINT(asBC_JMP, 0);
  2812. }
  2813. void asCCompiler::DestroyVariables(asCByteCode *bc)
  2814. {
  2815. // Call destructor on all variables except for the function parameters
  2816. // Put the clean-up in a block to allow exception handler to understand this
  2817. bc->Block(true);
  2818. asCVariableScope *vs = variables;
  2819. while( vs )
  2820. {
  2821. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2822. if( vs->variables[n]->stackOffset > 0 )
  2823. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2824. vs = vs->parent;
  2825. }
  2826. bc->Block(false);
  2827. }
  2828. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  2829. {
  2830. variables = asNEW(asCVariableScope)(variables);
  2831. variables->isBreakScope = isBreakScope;
  2832. variables->isContinueScope = isContinueScope;
  2833. }
  2834. void asCCompiler::RemoveVariableScope()
  2835. {
  2836. if( variables )
  2837. {
  2838. asCVariableScope *var = variables;
  2839. variables = variables->parent;
  2840. asDELETE(var,asCVariableScope);
  2841. }
  2842. }
  2843. void asCCompiler::Error(const char *msg, asCScriptNode *node)
  2844. {
  2845. asCString str;
  2846. int r = 0, c = 0;
  2847. asASSERT( node );
  2848. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2849. builder->WriteError(script->name.AddressOf(), msg, r, c);
  2850. hasCompileErrors = true;
  2851. }
  2852. void asCCompiler::Warning(const char *msg, asCScriptNode *node)
  2853. {
  2854. asCString str;
  2855. int r = 0, c = 0;
  2856. asASSERT( node );
  2857. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2858. builder->WriteWarning(script->name.AddressOf(), msg, r, c);
  2859. }
  2860. void asCCompiler::Information(const char *msg, asCScriptNode *node)
  2861. {
  2862. asCString str;
  2863. int r = 0, c = 0;
  2864. asASSERT( node );
  2865. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2866. builder->WriteInfo(script->name.AddressOf(), msg, r, c, false);
  2867. }
  2868. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  2869. {
  2870. int r = 0, c = 0;
  2871. asASSERT( node );
  2872. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2873. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  2874. {
  2875. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  2876. builder->WriteInfo(script->name.AddressOf(), func->GetDeclaration(true), r, c, false);
  2877. }
  2878. }
  2879. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  2880. {
  2881. int l = reservedVariables.GetLength();
  2882. ctx->bc.GetVarsUsed(reservedVariables);
  2883. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  2884. reservedVariables.SetLength(l);
  2885. return var;
  2886. }
  2887. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  2888. {
  2889. asCDataType t(type);
  2890. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  2891. t.SetTokenType(ttInt);
  2892. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  2893. t.SetTokenType(ttDouble);
  2894. // Only null handles have the token type unrecognized token
  2895. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  2896. bool isOnHeap = true;
  2897. // TODO: Remove this once the bugs with value types on stack is fixed
  2898. // forceOnHeap = true;
  2899. if( t.IsPrimitive() ||
  2900. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  2901. {
  2902. // Primitives and value types (unless overridden) are allocated on the stack
  2903. isOnHeap = false;
  2904. }
  2905. // Find a free location with the same type
  2906. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  2907. {
  2908. int slot = freeVariables[n];
  2909. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  2910. variableIsTemporary[slot] == isTemporary &&
  2911. variableIsOnHeap[slot] == isOnHeap )
  2912. {
  2913. // We can't return by slot, must count variable sizes
  2914. int offset = GetVariableOffset(slot);
  2915. // Verify that it is not in the list of reserved variables
  2916. bool isUsed = false;
  2917. if( reservedVariables.GetLength() )
  2918. isUsed = reservedVariables.Exists(offset);
  2919. if( !isUsed )
  2920. {
  2921. if( n != freeVariables.GetLength() - 1 )
  2922. freeVariables[n] = freeVariables.PopLast();
  2923. else
  2924. freeVariables.PopLast();
  2925. if( isTemporary )
  2926. tempVariables.PushLast(offset);
  2927. return offset;
  2928. }
  2929. }
  2930. }
  2931. variableAllocations.PushLast(t);
  2932. variableIsTemporary.PushLast(isTemporary);
  2933. variableIsOnHeap.PushLast(isOnHeap);
  2934. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  2935. if( isTemporary )
  2936. tempVariables.PushLast(offset);
  2937. return offset;
  2938. }
  2939. int asCCompiler::GetVariableOffset(int varIndex)
  2940. {
  2941. // Return offset to the last dword on the stack
  2942. int varOffset = 1;
  2943. for( int n = 0; n < varIndex; n++ )
  2944. {
  2945. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2946. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  2947. else
  2948. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  2949. }
  2950. if( varIndex < (int)variableAllocations.GetLength() )
  2951. {
  2952. int size;
  2953. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  2954. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  2955. else
  2956. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  2957. if( size > 1 )
  2958. varOffset += size-1;
  2959. }
  2960. return varOffset;
  2961. }
  2962. int asCCompiler::GetVariableSlot(int offset)
  2963. {
  2964. int varOffset = 1;
  2965. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  2966. {
  2967. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2968. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  2969. else
  2970. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  2971. if( varOffset == offset )
  2972. return n;
  2973. varOffset++;
  2974. }
  2975. return -1;
  2976. }
  2977. bool asCCompiler::IsVariableOnHeap(int offset)
  2978. {
  2979. int varSlot = GetVariableSlot(offset);
  2980. if( varSlot < 0 )
  2981. {
  2982. // This happens for function arguments that are considered as on the heap
  2983. return true;
  2984. }
  2985. return variableIsOnHeap[varSlot];
  2986. }
  2987. void asCCompiler::DeallocateVariable(int offset)
  2988. {
  2989. // Remove temporary variable
  2990. int n;
  2991. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  2992. {
  2993. if( offset == tempVariables[n] )
  2994. {
  2995. if( n == (int)tempVariables.GetLength()-1 )
  2996. tempVariables.PopLast();
  2997. else
  2998. tempVariables[n] = tempVariables.PopLast();
  2999. break;
  3000. }
  3001. }
  3002. n = GetVariableSlot(offset);
  3003. if( n != -1 )
  3004. {
  3005. freeVariables.PushLast(n);
  3006. return;
  3007. }
  3008. // We might get here if the variable was implicitly declared
  3009. // because it was use before a formal declaration, in this case
  3010. // the offset is 0x7FFF
  3011. asASSERT(offset == 0x7FFF);
  3012. }
  3013. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  3014. {
  3015. if( t.isTemporary )
  3016. {
  3017. ReleaseTemporaryVariable(t.stackOffset, bc);
  3018. t.isTemporary = false;
  3019. }
  3020. }
  3021. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  3022. {
  3023. if( bc )
  3024. {
  3025. // We need to call the destructor on the true variable type
  3026. int n = GetVariableSlot(offset);
  3027. asASSERT( n >= 0 );
  3028. if( n >= 0 )
  3029. {
  3030. asCDataType dt = variableAllocations[n];
  3031. bool isOnHeap = variableIsOnHeap[n];
  3032. // Call destructor
  3033. CallDestructor(dt, offset, isOnHeap, bc);
  3034. }
  3035. }
  3036. DeallocateVariable(offset);
  3037. }
  3038. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  3039. {
  3040. if( ctx->type.dataType.IsReference() )
  3041. {
  3042. if( ctx->type.dataType.IsObject() )
  3043. {
  3044. ctx->type.dataType.MakeReference(false);
  3045. if( generateCode )
  3046. {
  3047. ctx->bc.Instr(asBC_CHKREF);
  3048. ctx->bc.Instr(asBC_RDSPTR);
  3049. }
  3050. }
  3051. else
  3052. {
  3053. // This should never happen as primitives are treated differently
  3054. asASSERT(false);
  3055. }
  3056. }
  3057. }
  3058. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  3059. {
  3060. // Temporary variables are assumed to be initialized
  3061. if( type->isTemporary ) return true;
  3062. // Verify that it is a variable
  3063. if( !type->isVariable ) return true;
  3064. // Find the variable
  3065. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  3066. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  3067. if( v == 0 ) return true;
  3068. if( v->isInitialized ) return true;
  3069. // Complex types don't need this test
  3070. if( v->type.IsObject() ) return true;
  3071. // Mark as initialized so that the user will not be bothered again
  3072. v->isInitialized = true;
  3073. // Write warning
  3074. asCString str;
  3075. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  3076. Warning(str.AddressOf(), node);
  3077. return false;
  3078. }
  3079. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  3080. {
  3081. // Check if the variable is initialized (if it indeed is a variable)
  3082. IsVariableInitialized(&ctx->type, node);
  3083. asCDataType to = ctx->type.dataType;
  3084. to.MakeReference(false);
  3085. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  3086. ProcessDeferredParams(ctx);
  3087. }
  3088. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  3089. {
  3090. ProcessPropertyGetAccessor(rctx, node);
  3091. // Make sure the rvalue is initialized if it is a variable
  3092. IsVariableInitialized(&rctx->type, node);
  3093. if( lvalue->IsPrimitive() )
  3094. {
  3095. if( rctx->type.dataType.IsPrimitive() )
  3096. {
  3097. if( rctx->type.dataType.IsReference() )
  3098. {
  3099. // Cannot do implicit conversion of references so we first convert the reference to a variable
  3100. ConvertToVariableNotIn(rctx, lvalueExpr);
  3101. }
  3102. }
  3103. // Implicitly convert the value to the right type
  3104. int l = reservedVariables.GetLength();
  3105. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  3106. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  3107. reservedVariables.SetLength(l);
  3108. // Check data type
  3109. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3110. {
  3111. asCString str;
  3112. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3113. Error(str.AddressOf(), node);
  3114. rctx->type.SetDummy();
  3115. }
  3116. // Make sure the rvalue is a variable
  3117. if( !rctx->type.isVariable )
  3118. ConvertToVariableNotIn(rctx, lvalueExpr);
  3119. }
  3120. else
  3121. {
  3122. asCDataType to = *lvalue;
  3123. to.MakeReference(false);
  3124. // TODO: ImplicitConversion should know to do this by itself
  3125. // First convert to a handle which will do a reference cast
  3126. if( !lvalue->IsObjectHandle() &&
  3127. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3128. to.MakeHandle(true);
  3129. // Don't allow the implicit conversion to create an object
  3130. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3131. if( !lvalue->IsObjectHandle() &&
  3132. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3133. {
  3134. // Then convert to a reference, which will validate the handle
  3135. to.MakeHandle(false);
  3136. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3137. }
  3138. // Check data type
  3139. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3140. {
  3141. asCString str;
  3142. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3143. Error(str.AddressOf(), node);
  3144. }
  3145. else
  3146. {
  3147. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3148. if( lvalue->IsObject() )
  3149. asASSERT(!rctx->type.dataType.IsReference());
  3150. }
  3151. }
  3152. }
  3153. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3154. {
  3155. if( !type.isLValue ) return false;
  3156. if( type.dataType.IsReadOnly() ) return false;
  3157. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3158. return true;
  3159. }
  3160. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3161. {
  3162. if( lvalue->dataType.IsReadOnly() )
  3163. {
  3164. Error(TXT_REF_IS_READ_ONLY, node);
  3165. return -1;
  3166. }
  3167. if( lvalue->dataType.IsPrimitive() )
  3168. {
  3169. if( lvalue->isVariable )
  3170. {
  3171. // Copy the value between the variables directly
  3172. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3173. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3174. else
  3175. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3176. // Mark variable as initialized
  3177. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3178. if( v ) v->isInitialized = true;
  3179. }
  3180. else if( lvalue->dataType.IsReference() )
  3181. {
  3182. // Copy the value of the variable to the reference in the register
  3183. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3184. if( s == 1 )
  3185. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3186. else if( s == 2 )
  3187. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3188. else if( s == 4 )
  3189. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3190. else if( s == 8 )
  3191. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3192. }
  3193. else
  3194. {
  3195. Error(TXT_NOT_VALID_LVALUE, node);
  3196. return -1;
  3197. }
  3198. }
  3199. else if( !lvalue->isExplicitHandle )
  3200. {
  3201. asSExprContext ctx(engine);
  3202. ctx.type = *lvalue;
  3203. Dereference(&ctx, true);
  3204. *lvalue = ctx.type;
  3205. bc->AddCode(&ctx.bc);
  3206. // TODO: Can't this leave deferred output params unhandled?
  3207. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3208. // The beh->copy member will be removed.
  3209. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3210. if( beh->copy )
  3211. {
  3212. // Call the copy operator
  3213. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  3214. bc->Instr(asBC_PshRPtr);
  3215. }
  3216. else
  3217. {
  3218. // Default copy operator
  3219. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3220. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3221. {
  3222. asCString msg;
  3223. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  3224. Error(msg.AddressOf(), node);
  3225. return -1;
  3226. }
  3227. // Copy larger data types from a reference
  3228. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3229. }
  3230. }
  3231. else
  3232. {
  3233. // TODO: The object handle can be stored in a variable as well
  3234. if( !lvalue->dataType.IsReference() )
  3235. {
  3236. Error(TXT_NOT_VALID_REFERENCE, node);
  3237. return -1;
  3238. }
  3239. // TODO: optimize: Convert to register based
  3240. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3241. // Mark variable as initialized
  3242. if( variables )
  3243. {
  3244. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3245. if( v ) v->isInitialized = true;
  3246. }
  3247. }
  3248. return 0;
  3249. }
  3250. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3251. {
  3252. bool conversionDone = false;
  3253. asCArray<int> ops;
  3254. asUINT n;
  3255. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3256. {
  3257. // We need it to be a reference
  3258. if( !ctx->type.dataType.IsReference() )
  3259. {
  3260. asCDataType to = ctx->type.dataType;
  3261. to.MakeReference(true);
  3262. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3263. }
  3264. if( isExplicit )
  3265. {
  3266. // Allow dynamic cast between object handles (only for script objects).
  3267. // At run time this may result in a null handle,
  3268. // which when used will throw an exception
  3269. conversionDone = true;
  3270. if( generateCode )
  3271. {
  3272. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3273. // Allocate a temporary variable for the returned object
  3274. int returnOffset = AllocateVariable(to, true);
  3275. // Move the pointer from the object register to the temporary variable
  3276. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3277. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3278. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3279. ctx->type.SetVariable(to, returnOffset, true);
  3280. ctx->type.dataType.MakeReference(true);
  3281. }
  3282. else
  3283. {
  3284. ctx->type.dataType = to;
  3285. ctx->type.dataType.MakeReference(true);
  3286. }
  3287. }
  3288. else
  3289. {
  3290. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3291. {
  3292. conversionDone = true;
  3293. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3294. }
  3295. }
  3296. }
  3297. else
  3298. {
  3299. // Find a suitable registered behaviour
  3300. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3301. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3302. {
  3303. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3304. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3305. {
  3306. int funcId = beh->operators[n+1];
  3307. // Is the operator for the output type?
  3308. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3309. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3310. continue;
  3311. ops.PushLast(funcId);
  3312. }
  3313. }
  3314. // It shouldn't be possible to have more than one
  3315. asASSERT( ops.GetLength() <= 1 );
  3316. // Should only have one behaviour for each output type
  3317. if( ops.GetLength() == 1 )
  3318. {
  3319. if( generateCode )
  3320. {
  3321. // TODO: optimize: Instead of producing bytecode for checking if the handle is
  3322. // null, we can create a special CALLSYS instruction that checks
  3323. // if the object pointer is null and if so sets the object register
  3324. // to null directly without executing the function.
  3325. //
  3326. // Alternatively I could force the ref cast behaviours be global
  3327. // functions with 1 parameter, even though they should still be
  3328. // registered with RegisterObjectBehaviour()
  3329. // Add code to avoid calling the cast behaviour if the handle is already null,
  3330. // because that will raise a null pointer exception due to the cast behaviour
  3331. // being a class method, and the this pointer cannot be null.
  3332. if( ctx->type.isVariable )
  3333. ctx->bc.Pop(AS_PTR_SIZE);
  3334. else
  3335. {
  3336. Dereference(ctx, true);
  3337. ConvertToVariable(ctx);
  3338. }
  3339. #ifdef AS_64BIT_PTR
  3340. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt64, false), true);
  3341. ctx->bc.InstrW_QW(asBC_SetV8, (asWORD)offset, 0);
  3342. ctx->bc.InstrW_W(asBC_CMPi64, ctx->type.stackOffset, offset);
  3343. DeallocateVariable(offset);
  3344. #else
  3345. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt, false), true);
  3346. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  3347. ctx->bc.InstrW_W(asBC_CMPi, ctx->type.stackOffset, offset);
  3348. DeallocateVariable(offset);
  3349. #endif
  3350. int afterLabel = nextLabel++;
  3351. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3352. // Call the cast operator
  3353. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3354. ctx->bc.Instr(asBC_RDSPTR);
  3355. ctx->type.dataType.MakeReference(false);
  3356. asCTypeInfo objType = ctx->type;
  3357. asCArray<asSExprContext *> args;
  3358. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3359. ctx->bc.Pop(AS_PTR_SIZE);
  3360. int endLabel = nextLabel++;
  3361. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3362. ctx->bc.Label((short)afterLabel);
  3363. // Make a NULL pointer
  3364. #ifdef AS_64BIT_PTR
  3365. ctx->bc.InstrW_QW(asBC_SetV8, ctx->type.stackOffset, 0);
  3366. #else
  3367. ctx->bc.InstrW_DW(asBC_SetV4, ctx->type.stackOffset, 0);
  3368. #endif
  3369. ctx->bc.Label((short)endLabel);
  3370. // Since we're receiving a handle, we can release the original variable
  3371. ReleaseTemporaryVariable(objType, &ctx->bc);
  3372. // Push the reference to the handle on the stack
  3373. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3374. }
  3375. else
  3376. {
  3377. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3378. ctx->type.Set(func->returnType);
  3379. }
  3380. }
  3381. else if( ops.GetLength() == 0 )
  3382. {
  3383. // Check for the generic ref cast behaviour
  3384. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3385. {
  3386. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3387. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3388. {
  3389. int funcId = beh->operators[n+1];
  3390. // Does the operator take the ?&out parameter?
  3391. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3392. if( func->parameterTypes.GetLength() != 1 ||
  3393. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3394. func->inOutFlags[0] != asTM_OUTREF )
  3395. continue;
  3396. ops.PushLast(funcId);
  3397. }
  3398. }
  3399. // It shouldn't be possible to have more than one
  3400. asASSERT( ops.GetLength() <= 1 );
  3401. if( ops.GetLength() == 1 )
  3402. {
  3403. if( generateCode )
  3404. {
  3405. asASSERT(to.IsObjectHandle());
  3406. // Allocate a temporary variable of the requested handle type
  3407. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  3408. // Pass the reference of that variable to the function as output parameter
  3409. asCDataType toRef(to);
  3410. toRef.MakeReference(true);
  3411. asCArray<asSExprContext *> args;
  3412. asSExprContext arg(engine);
  3413. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3414. // Don't mark the variable as temporary, so it won't be freed too early
  3415. arg.type.SetVariable(toRef, stackOffset, false);
  3416. arg.type.isLValue = true;
  3417. arg.type.isExplicitHandle = true;
  3418. args.PushLast(&arg);
  3419. // Call the behaviour method
  3420. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  3421. // Use the reference to the variable as the result of the expression
  3422. // Now we can mark the variable as temporary
  3423. ctx->type.SetVariable(toRef, stackOffset, true);
  3424. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3425. }
  3426. else
  3427. {
  3428. // All casts are legal
  3429. ctx->type.Set(to);
  3430. }
  3431. }
  3432. }
  3433. }
  3434. return conversionDone;
  3435. }
  3436. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3437. {
  3438. asCDataType to = toOrig;
  3439. to.MakeReference(false);
  3440. asASSERT( !ctx->type.dataType.IsReference() );
  3441. // Maybe no conversion is needed
  3442. if( to.IsEqualExceptConst(ctx->type.dataType) )
  3443. {
  3444. // A primitive is const or not
  3445. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3446. return asCC_NO_CONV;
  3447. }
  3448. // Determine the cost of this conversion
  3449. asUINT cost = asCC_NO_CONV;
  3450. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  3451. cost = asCC_INT_FLOAT_CONV;
  3452. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
  3453. cost = asCC_INT_FLOAT_CONV;
  3454. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  3455. cost = asCC_SIGNED_CONV;
  3456. else if( to.IsIntegerType() && (ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType()) )
  3457. cost = asCC_SIGNED_CONV;
  3458. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  3459. cost = asCC_PRIMITIVE_SIZE_CONV;
  3460. // Start by implicitly converting constant values
  3461. if( ctx->type.isConstant )
  3462. {
  3463. ImplicitConversionConstant(ctx, to, node, convType);
  3464. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3465. return cost;
  3466. }
  3467. // Allow implicit conversion between numbers
  3468. if( generateCode )
  3469. {
  3470. // When generating the code the decision has already been made, so we don't bother determining the cost
  3471. // Convert smaller types to 32bit first
  3472. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3473. if( s < 4 )
  3474. {
  3475. ConvertToTempVariable(ctx);
  3476. if( ctx->type.dataType.IsIntegerType() )
  3477. {
  3478. if( s == 1 )
  3479. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3480. else if( s == 2 )
  3481. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3482. ctx->type.dataType.SetTokenType(ttInt);
  3483. }
  3484. else if( ctx->type.dataType.IsUnsignedType() )
  3485. {
  3486. if( s == 1 )
  3487. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3488. else if( s == 2 )
  3489. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3490. ctx->type.dataType.SetTokenType(ttUInt);
  3491. }
  3492. }
  3493. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3494. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3495. {
  3496. if( ctx->type.dataType.IsIntegerType() ||
  3497. ctx->type.dataType.IsUnsignedType() ||
  3498. ctx->type.dataType.IsEnumType() )
  3499. {
  3500. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3501. {
  3502. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3503. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3504. }
  3505. else
  3506. {
  3507. ConvertToTempVariable(ctx);
  3508. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3509. int offset = AllocateVariable(to, true);
  3510. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3511. ctx->type.SetVariable(to, offset, true);
  3512. }
  3513. }
  3514. else if( ctx->type.dataType.IsFloatType() )
  3515. {
  3516. ConvertToTempVariable(ctx);
  3517. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3518. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3519. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3520. }
  3521. else if( ctx->type.dataType.IsDoubleType() )
  3522. {
  3523. ConvertToTempVariable(ctx);
  3524. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3525. int offset = AllocateVariable(to, true);
  3526. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3527. ctx->type.SetVariable(to, offset, true);
  3528. }
  3529. // Convert to smaller integer if necessary
  3530. int s = to.GetSizeInMemoryBytes();
  3531. if( s < 4 )
  3532. {
  3533. ConvertToTempVariable(ctx);
  3534. if( s == 1 )
  3535. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3536. else if( s == 2 )
  3537. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3538. }
  3539. }
  3540. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3541. {
  3542. if( ctx->type.dataType.IsIntegerType() ||
  3543. ctx->type.dataType.IsUnsignedType() ||
  3544. ctx->type.dataType.IsEnumType() )
  3545. {
  3546. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3547. {
  3548. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3549. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3550. }
  3551. else
  3552. {
  3553. ConvertToTempVariable(ctx);
  3554. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3555. int offset = AllocateVariable(to, true);
  3556. if( ctx->type.dataType.IsUnsignedType() )
  3557. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3558. else
  3559. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3560. ctx->type.SetVariable(to, offset, true);
  3561. }
  3562. }
  3563. else if( ctx->type.dataType.IsFloatType() )
  3564. {
  3565. ConvertToTempVariable(ctx);
  3566. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3567. int offset = AllocateVariable(to, true);
  3568. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3569. ctx->type.SetVariable(to, offset, true);
  3570. }
  3571. else if( ctx->type.dataType.IsDoubleType() )
  3572. {
  3573. ConvertToTempVariable(ctx);
  3574. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3575. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3576. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3577. }
  3578. }
  3579. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3580. {
  3581. if( ctx->type.dataType.IsIntegerType() ||
  3582. ctx->type.dataType.IsUnsignedType() ||
  3583. ctx->type.dataType.IsEnumType() )
  3584. {
  3585. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3586. {
  3587. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3588. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3589. }
  3590. else
  3591. {
  3592. ConvertToTempVariable(ctx);
  3593. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3594. int offset = AllocateVariable(to, true);
  3595. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3596. ctx->type.SetVariable(to, offset, true);
  3597. }
  3598. }
  3599. else if( ctx->type.dataType.IsFloatType() )
  3600. {
  3601. ConvertToTempVariable(ctx);
  3602. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3603. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3604. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3605. }
  3606. else if( ctx->type.dataType.IsDoubleType() )
  3607. {
  3608. ConvertToTempVariable(ctx);
  3609. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3610. int offset = AllocateVariable(to, true);
  3611. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3612. ctx->type.SetVariable(to, offset, true);
  3613. }
  3614. // Convert to smaller integer if necessary
  3615. int s = to.GetSizeInMemoryBytes();
  3616. if( s < 4 )
  3617. {
  3618. ConvertToTempVariable(ctx);
  3619. if( s == 1 )
  3620. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3621. else if( s == 2 )
  3622. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3623. }
  3624. }
  3625. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3626. {
  3627. if( ctx->type.dataType.IsIntegerType() ||
  3628. ctx->type.dataType.IsUnsignedType() ||
  3629. ctx->type.dataType.IsEnumType() )
  3630. {
  3631. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3632. {
  3633. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3634. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3635. }
  3636. else
  3637. {
  3638. ConvertToTempVariable(ctx);
  3639. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3640. int offset = AllocateVariable(to, true);
  3641. if( ctx->type.dataType.IsUnsignedType() )
  3642. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3643. else
  3644. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3645. ctx->type.SetVariable(to, offset, true);
  3646. }
  3647. }
  3648. else if( ctx->type.dataType.IsFloatType() )
  3649. {
  3650. ConvertToTempVariable(ctx);
  3651. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3652. int offset = AllocateVariable(to, true);
  3653. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3654. ctx->type.SetVariable(to, offset, true);
  3655. }
  3656. else if( ctx->type.dataType.IsDoubleType() )
  3657. {
  3658. ConvertToTempVariable(ctx);
  3659. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3660. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3661. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3662. }
  3663. }
  3664. else if( to.IsFloatType() )
  3665. {
  3666. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3667. {
  3668. ConvertToTempVariable(ctx);
  3669. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3670. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3671. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3672. }
  3673. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3674. {
  3675. ConvertToTempVariable(ctx);
  3676. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3677. int offset = AllocateVariable(to, true);
  3678. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  3679. ctx->type.SetVariable(to, offset, true);
  3680. }
  3681. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3682. {
  3683. ConvertToTempVariable(ctx);
  3684. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  3685. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3686. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3687. }
  3688. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3689. {
  3690. ConvertToTempVariable(ctx);
  3691. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3692. int offset = AllocateVariable(to, true);
  3693. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  3694. ctx->type.SetVariable(to, offset, true);
  3695. }
  3696. else if( ctx->type.dataType.IsDoubleType() )
  3697. {
  3698. ConvertToTempVariable(ctx);
  3699. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3700. int offset = AllocateVariable(to, true);
  3701. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  3702. ctx->type.SetVariable(to, offset, true);
  3703. }
  3704. }
  3705. else if( to.IsDoubleType() )
  3706. {
  3707. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3708. {
  3709. ConvertToTempVariable(ctx);
  3710. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3711. int offset = AllocateVariable(to, true);
  3712. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  3713. ctx->type.SetVariable(to, offset, true);
  3714. }
  3715. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3716. {
  3717. ConvertToTempVariable(ctx);
  3718. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  3719. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3720. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3721. }
  3722. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3723. {
  3724. ConvertToTempVariable(ctx);
  3725. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3726. int offset = AllocateVariable(to, true);
  3727. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  3728. ctx->type.SetVariable(to, offset, true);
  3729. }
  3730. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3731. {
  3732. ConvertToTempVariable(ctx);
  3733. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  3734. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3735. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3736. }
  3737. else if( ctx->type.dataType.IsFloatType() )
  3738. {
  3739. ConvertToTempVariable(ctx);
  3740. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3741. int offset = AllocateVariable(to, true);
  3742. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  3743. ctx->type.SetVariable(to, offset, true);
  3744. }
  3745. }
  3746. }
  3747. else
  3748. {
  3749. if( (to.IsIntegerType() || to.IsUnsignedType() ||
  3750. to.IsFloatType() || to.IsDoubleType() ||
  3751. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  3752. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  3753. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
  3754. ctx->type.dataType.IsEnumType()) )
  3755. {
  3756. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3757. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3758. }
  3759. }
  3760. // Primitive types on the stack, can be const or non-const
  3761. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3762. return cost;
  3763. }
  3764. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  3765. {
  3766. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  3767. ctx->type.dataType.IsNullHandle() );
  3768. // No conversion from void to any other type
  3769. if( ctx->type.dataType.GetTokenType() == ttVoid )
  3770. return asCC_NO_CONV;
  3771. // Do we want a var type?
  3772. if( to.GetTokenType() == ttQuestion )
  3773. {
  3774. // Any type can be converted to a var type, but only when not generating code
  3775. asASSERT( !generateCode );
  3776. ctx->type.dataType = to;
  3777. return asCC_VARIABLE_CONV;
  3778. }
  3779. // Do we want a primitive?
  3780. else if( to.IsPrimitive() )
  3781. {
  3782. if( !ctx->type.dataType.IsPrimitive() )
  3783. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  3784. else
  3785. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  3786. }
  3787. else // The target is a complex type
  3788. {
  3789. if( ctx->type.dataType.IsPrimitive() )
  3790. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  3791. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  3792. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  3793. }
  3794. return asCC_NO_CONV;
  3795. }
  3796. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3797. {
  3798. if( ctx->type.isExplicitHandle )
  3799. {
  3800. // An explicit handle cannot be converted to a primitive
  3801. if( convType != asIC_IMPLICIT_CONV && node )
  3802. {
  3803. asCString str;
  3804. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3805. Error(str.AddressOf(), node);
  3806. }
  3807. return asCC_NO_CONV;
  3808. }
  3809. // TODO: Must use the const cast behaviour if the object is read-only
  3810. // Find matching value cast behaviours
  3811. // Here we're only interested in those that convert the type to a primitive type
  3812. asCArray<int> funcs;
  3813. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3814. if( beh )
  3815. {
  3816. if( convType == asIC_EXPLICIT_VAL_CAST )
  3817. {
  3818. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3819. {
  3820. // accept both implicit and explicit cast
  3821. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3822. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3823. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3824. funcs.PushLast(beh->operators[n+1]);
  3825. }
  3826. }
  3827. else
  3828. {
  3829. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3830. {
  3831. // accept only implicit cast
  3832. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3833. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3834. funcs.PushLast(beh->operators[n+1]);
  3835. }
  3836. }
  3837. }
  3838. // This matrix describes the priorities of the types to search for, for each target type
  3839. // The first column is the target type, the priorities goes from left to right
  3840. eTokenType matchMtx[10][10] =
  3841. {
  3842. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3843. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3844. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3845. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3846. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3847. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3848. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  3849. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  3850. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  3851. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  3852. };
  3853. // Which row to use?
  3854. eTokenType *row = 0;
  3855. for( unsigned int type = 0; type < 10; type++ )
  3856. {
  3857. if( to.GetTokenType() == matchMtx[type][0] )
  3858. {
  3859. row = &matchMtx[type][0];
  3860. break;
  3861. }
  3862. }
  3863. // Find the best matching cast operator
  3864. int funcId = 0;
  3865. if( row )
  3866. {
  3867. asCDataType target(to);
  3868. // Priority goes from left to right in the matrix
  3869. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  3870. {
  3871. target.SetTokenType(row[attempt]);
  3872. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3873. {
  3874. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  3875. if( descr->returnType.IsEqualExceptConst(target) )
  3876. {
  3877. funcId = funcs[n];
  3878. break;
  3879. }
  3880. }
  3881. }
  3882. }
  3883. // Did we find a suitable function?
  3884. if( funcId != 0 )
  3885. {
  3886. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  3887. if( generateCode )
  3888. {
  3889. asCTypeInfo objType = ctx->type;
  3890. Dereference(ctx, true);
  3891. PerformFunctionCall(funcId, ctx);
  3892. ReleaseTemporaryVariable(objType, &ctx->bc);
  3893. }
  3894. else
  3895. ctx->type.Set(descr->returnType);
  3896. // Allow one more implicit conversion to another primitive type
  3897. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  3898. }
  3899. else
  3900. {
  3901. if( convType != asIC_IMPLICIT_CONV && node )
  3902. {
  3903. asCString str;
  3904. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3905. Error(str.AddressOf(), node);
  3906. }
  3907. }
  3908. return asCC_NO_CONV;
  3909. }
  3910. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3911. {
  3912. // Convert null to any object type handle, but not to a non-handle type
  3913. if( ctx->type.IsNullConstant() )
  3914. {
  3915. if( to.IsObjectHandle() )
  3916. {
  3917. ctx->type.dataType = to;
  3918. return asCC_REF_CONV;
  3919. }
  3920. return asCC_NO_CONV;
  3921. }
  3922. asASSERT(ctx->type.dataType.GetObjectType());
  3923. // First attempt to convert the base type without instanciating another instance
  3924. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3925. {
  3926. // If the to type is an interface and the from type implements it, then we can convert it immediately
  3927. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  3928. {
  3929. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3930. return asCC_REF_CONV;
  3931. }
  3932. // If the to type is a class and the from type derives from it, then we can convert it immediately
  3933. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3934. {
  3935. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3936. return asCC_REF_CONV;
  3937. }
  3938. // If the types are not equal yet, then we may still be able to find a reference cast
  3939. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  3940. {
  3941. // A ref cast must not remove the constness
  3942. bool isConst = false;
  3943. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  3944. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  3945. isConst = true;
  3946. // We may still be able to find an implicit ref cast behaviour
  3947. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  3948. ctx->type.dataType.MakeHandleToConst(isConst);
  3949. // Was the conversion done?
  3950. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  3951. return asCC_REF_CONV;
  3952. }
  3953. }
  3954. // Convert matching function types
  3955. if( to.GetFuncDef() && ctx->type.dataType.GetFuncDef() &&
  3956. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  3957. {
  3958. asCScriptFunction *toFunc = to.GetFuncDef();
  3959. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  3960. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  3961. {
  3962. ctx->type.dataType.SetFuncDef(toFunc);
  3963. return asCC_REF_CONV;
  3964. }
  3965. }
  3966. return asCC_NO_CONV;
  3967. }
  3968. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv convType, bool generateCode)
  3969. {
  3970. asUINT cost = asCC_NO_CONV;
  3971. // If the base type is still different, and we are allowed to instance
  3972. // another object then we can try an implicit value cast
  3973. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3974. {
  3975. // TODO: Implement support for implicit constructor/factory
  3976. asCArray<int> funcs;
  3977. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3978. if( beh )
  3979. {
  3980. if( convType == asIC_EXPLICIT_VAL_CAST )
  3981. {
  3982. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3983. {
  3984. // accept both implicit and explicit cast
  3985. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3986. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3987. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3988. funcs.PushLast(beh->operators[n+1]);
  3989. }
  3990. }
  3991. else
  3992. {
  3993. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3994. {
  3995. // accept only implicit cast
  3996. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3997. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3998. funcs.PushLast(beh->operators[n+1]);
  3999. }
  4000. }
  4001. }
  4002. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  4003. asASSERT( funcs.GetLength() <= 1 );
  4004. if( funcs.GetLength() == 1 )
  4005. {
  4006. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  4007. if( generateCode )
  4008. {
  4009. asCTypeInfo objType = ctx->type;
  4010. Dereference(ctx, true);
  4011. bool useVariable = false;
  4012. int stackOffset = 0;
  4013. #ifndef AS_OLD
  4014. if( f->DoesReturnOnStack() )
  4015. {
  4016. useVariable = true;
  4017. stackOffset = AllocateVariable(f->returnType, true);
  4018. // Push the pointer to the pre-allocated space for the return value
  4019. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  4020. // The object pointer is already on the stack, but should be the top
  4021. // one, so we need to swap the pointers in order to get the correct
  4022. #if AS_PTR_SIZE == 1
  4023. ctx->bc.Instr(asBC_SWAP4);
  4024. #else
  4025. ctx->bc.Instr(asBC_SWAP8);
  4026. #endif
  4027. }
  4028. #endif
  4029. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  4030. ReleaseTemporaryVariable(objType, &ctx->bc);
  4031. }
  4032. else
  4033. ctx->type.Set(f->returnType);
  4034. cost = asCC_TO_OBJECT_CONV;
  4035. }
  4036. }
  4037. return cost;
  4038. }
  4039. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4040. {
  4041. // First try a ref cast
  4042. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  4043. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  4044. // construct the object through any of the available constructors
  4045. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4046. {
  4047. asCArray<int> funcs;
  4048. funcs = to.GetObjectType()->beh.constructors;
  4049. asCArray<asSExprContext *> args;
  4050. args.PushLast(ctx);
  4051. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, false, true, false);
  4052. // Did we find a matching constructor?
  4053. if( funcs.GetLength() == 1 )
  4054. {
  4055. if( generateCode )
  4056. {
  4057. // TODO: This should really reuse the code from CompileConstructCall
  4058. // Allocate the new object
  4059. asCTypeInfo tempObj;
  4060. tempObj.dataType = to;
  4061. tempObj.dataType.MakeReference(false);
  4062. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  4063. tempObj.dataType.MakeReference(true);
  4064. tempObj.isTemporary = true;
  4065. tempObj.isVariable = true;
  4066. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4067. // Push the address of the object on the stack
  4068. asSExprContext e(engine);
  4069. if( onHeap )
  4070. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4071. PrepareFunctionCall(funcs[0], &e.bc, args);
  4072. MoveArgsToStack(funcs[0], &e.bc, args, false);
  4073. // If the object is allocated on the stack, then call the constructor as a normal function
  4074. if( onHeap )
  4075. {
  4076. int offset = 0;
  4077. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4078. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  4079. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4080. }
  4081. else
  4082. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4083. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  4084. // Add tag that the object has been initialized
  4085. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4086. // The constructor doesn't return anything,
  4087. // so we have to manually inform the type of
  4088. // the return value
  4089. e.type = tempObj;
  4090. if( !onHeap )
  4091. e.type.dataType.MakeReference(false);
  4092. // Push the address of the object on the stack again
  4093. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4094. MergeExprBytecodeAndType(ctx, &e);
  4095. }
  4096. else
  4097. {
  4098. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  4099. }
  4100. }
  4101. }
  4102. // If the base type is still different, and we are allowed to instance
  4103. // another object then we can try an implicit value cast
  4104. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4105. {
  4106. // Attempt implicit value cast
  4107. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  4108. }
  4109. // If we still haven't converted the base type to the correct type, then there is
  4110. // no need to continue as it is not possible to do the conversion
  4111. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4112. return asCC_NO_CONV;
  4113. if( to.IsObjectHandle() )
  4114. {
  4115. // There is no extra cost in converting to a handle
  4116. // reference to handle -> handle
  4117. // reference -> handle
  4118. // object -> handle
  4119. // handle -> reference to handle
  4120. // reference -> reference to handle
  4121. // object -> reference to handle
  4122. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  4123. // If the rvalue is a handle to a const object, then
  4124. // the lvalue must also be a handle to a const object
  4125. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  4126. {
  4127. if( convType != asIC_IMPLICIT_CONV )
  4128. {
  4129. asASSERT(node);
  4130. asCString str;
  4131. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4132. Error(str.AddressOf(), node);
  4133. }
  4134. }
  4135. if( !ctx->type.dataType.IsObjectHandle() )
  4136. {
  4137. // An object type can be directly converted to a handle of the same type
  4138. if( ctx->type.dataType.SupportHandles() )
  4139. {
  4140. ctx->type.dataType.MakeHandle(true);
  4141. }
  4142. if( ctx->type.dataType.IsObjectHandle() )
  4143. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4144. if( to.IsHandleToConst() && ctx->type.dataType.IsObjectHandle() )
  4145. ctx->type.dataType.MakeHandleToConst(true);
  4146. }
  4147. else
  4148. {
  4149. // A handle to non-const can be converted to a
  4150. // handle to const, but not the other way
  4151. if( to.IsHandleToConst() )
  4152. ctx->type.dataType.MakeHandleToConst(true);
  4153. // A const handle can be converted to a non-const
  4154. // handle and vice versa as the handle is just a value
  4155. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4156. }
  4157. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4158. {
  4159. if( generateCode )
  4160. {
  4161. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4162. // If the input type is a handle, then a simple ref copy is enough
  4163. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4164. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  4165. // If the input type is read-only we'll need to temporarily
  4166. // remove this constness, otherwise the assignment will fail
  4167. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4168. ctx->type.dataType.MakeReadOnly(false);
  4169. // If the object already is a temporary variable, then the copy
  4170. // doesn't have to be made as it is already a unique object
  4171. PrepareTemporaryObject(node, ctx);
  4172. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4173. ctx->type.isExplicitHandle = isExplicitHandle;
  4174. }
  4175. // A non-reference can be converted to a reference,
  4176. // by putting the value in a temporary variable
  4177. ctx->type.dataType.MakeReference(true);
  4178. // Since it is a new temporary variable it doesn't have to be const
  4179. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4180. }
  4181. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  4182. {
  4183. Dereference(ctx, generateCode);
  4184. }
  4185. }
  4186. else
  4187. {
  4188. if( !to.IsReference() )
  4189. {
  4190. // reference to handle -> object
  4191. // handle -> object
  4192. // reference -> object
  4193. // An implicit handle can be converted to an object by adding a check for null pointer
  4194. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4195. {
  4196. if( generateCode )
  4197. ctx->bc.Instr(asBC_CHKREF);
  4198. ctx->type.dataType.MakeHandle(false);
  4199. }
  4200. // A const object can be converted to a non-const object through a copy
  4201. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  4202. allowObjectConstruct )
  4203. {
  4204. // Does the object type allow a copy to be made?
  4205. if( ctx->type.dataType.CanBeCopied() )
  4206. {
  4207. if( generateCode )
  4208. {
  4209. // Make a temporary object with the copy
  4210. PrepareTemporaryObject(node, ctx);
  4211. }
  4212. // In case the object was already in a temporary variable, then the function
  4213. // didn't really do anything so we need to remove the constness here
  4214. ctx->type.dataType.MakeReadOnly(false);
  4215. // Add the cost for the copy
  4216. cost += asCC_TO_OBJECT_CONV;
  4217. }
  4218. }
  4219. if( ctx->type.dataType.IsReference() )
  4220. {
  4221. // This may look strange, but a value type allocated on the stack is already
  4222. // correct, so nothing should be done other than remove the mark as reference.
  4223. // For types allocated on the heap, it is necessary to dereference the pointer
  4224. // that is currently on the stack
  4225. if( IsVariableOnHeap(ctx->type.stackOffset) )
  4226. Dereference(ctx, generateCode);
  4227. else
  4228. ctx->type.dataType.MakeReference(false);
  4229. }
  4230. // A non-const object can be converted to a const object directly
  4231. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4232. {
  4233. ctx->type.dataType.MakeReadOnly(true);
  4234. }
  4235. }
  4236. else
  4237. {
  4238. // reference to handle -> reference
  4239. // handle -> reference
  4240. // object -> reference
  4241. if( ctx->type.dataType.IsReference() )
  4242. {
  4243. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4244. {
  4245. // ASHANDLE objects are really value types, so explicit handle can be removed
  4246. ctx->type.isExplicitHandle = false;
  4247. ctx->type.dataType.MakeHandle(false);
  4248. }
  4249. // A reference to a handle can be converted to a reference to an object
  4250. // by first reading the address, then verifying that it is not null
  4251. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4252. {
  4253. ctx->type.dataType.MakeHandle(false);
  4254. if( generateCode )
  4255. ctx->bc.Instr(asBC_ChkRefS);
  4256. }
  4257. // A reference to a non-const can be converted to a reference to a const
  4258. if( to.IsReadOnly() )
  4259. ctx->type.dataType.MakeReadOnly(true);
  4260. else if( ctx->type.dataType.IsReadOnly() )
  4261. {
  4262. // A reference to a const can be converted to a reference to a
  4263. // non-const by copying the object to a temporary variable
  4264. ctx->type.dataType.MakeReadOnly(false);
  4265. if( generateCode )
  4266. {
  4267. // If the object already is a temporary variable, then the copy
  4268. // doesn't have to be made as it is already a unique object
  4269. PrepareTemporaryObject(node, ctx);
  4270. }
  4271. // Add the cost for the copy
  4272. cost += asCC_TO_OBJECT_CONV;
  4273. }
  4274. }
  4275. else
  4276. {
  4277. // A value type allocated on the stack is differentiated
  4278. // by it not being a reference. But it can be handled as
  4279. // reference by pushing the pointer on the stack
  4280. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  4281. (ctx->type.isVariable || ctx->type.isTemporary) &&
  4282. !IsVariableOnHeap(ctx->type.stackOffset) )
  4283. {
  4284. // Actually the pointer is already pushed on the stack in
  4285. // CompileVariableAccess, so we don't need to do anything else
  4286. }
  4287. else if( generateCode )
  4288. {
  4289. // A non-reference can be converted to a reference,
  4290. // by putting the value in a temporary variable
  4291. // If the input type is read-only we'll need to temporarily
  4292. // remove this constness, otherwise the assignment will fail
  4293. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4294. ctx->type.dataType.MakeReadOnly(false);
  4295. // If the object already is a temporary variable, then the copy
  4296. // doesn't have to be made as it is already a unique object
  4297. PrepareTemporaryObject(node, ctx);
  4298. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4299. // Add the cost for the copy
  4300. cost += asCC_TO_OBJECT_CONV;
  4301. }
  4302. // A handle can be converted to a reference, by checking for a null pointer
  4303. if( ctx->type.dataType.IsObjectHandle() )
  4304. {
  4305. if( generateCode )
  4306. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4307. ctx->type.dataType.MakeHandle(false);
  4308. ctx->type.dataType.MakeReference(true);
  4309. // TODO: Make sure a handle to const isn't converted to non-const reference
  4310. }
  4311. else
  4312. {
  4313. // This may look strange as the conversion was to make the expression a reference
  4314. // but a value type allocated on the stack is a reference even without the type
  4315. // being marked as such.
  4316. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4317. }
  4318. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  4319. // Since it is a new temporary variable it doesn't have to be const
  4320. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4321. }
  4322. }
  4323. }
  4324. return cost;
  4325. }
  4326. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, bool /*allowObjectConstruct*/)
  4327. {
  4328. // TODO: This function should call the constructor/factory that has been marked as available
  4329. // for implicit conversions. The code will likely be similar to CallCopyConstructor()
  4330. return asCC_NO_CONV;
  4331. }
  4332. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  4333. {
  4334. asASSERT(from->type.isConstant);
  4335. // TODO: node should be the node of the value that is
  4336. // converted (not the operator that provokes the implicit
  4337. // conversion)
  4338. // If the base type is correct there is no more to do
  4339. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  4340. // References cannot be constants
  4341. if( from->type.dataType.IsReference() ) return;
  4342. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  4343. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4344. {
  4345. if( from->type.dataType.IsFloatType() ||
  4346. from->type.dataType.IsDoubleType() ||
  4347. from->type.dataType.IsUnsignedType() ||
  4348. from->type.dataType.IsIntegerType() ||
  4349. from->type.dataType.IsEnumType() )
  4350. {
  4351. // Transform the value
  4352. // Float constants can be implicitly converted to int
  4353. if( from->type.dataType.IsFloatType() )
  4354. {
  4355. float fc = from->type.floatValue;
  4356. int ic = int(fc);
  4357. if( float(ic) != fc )
  4358. {
  4359. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4360. }
  4361. from->type.intValue = ic;
  4362. }
  4363. // Double constants can be implicitly converted to int
  4364. else if( from->type.dataType.IsDoubleType() )
  4365. {
  4366. double fc = from->type.doubleValue;
  4367. int ic = int(fc);
  4368. if( double(ic) != fc )
  4369. {
  4370. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4371. }
  4372. from->type.intValue = ic;
  4373. }
  4374. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4375. {
  4376. // Verify that it is possible to convert to signed without getting negative
  4377. if( from->type.intValue < 0 )
  4378. {
  4379. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4380. }
  4381. // Convert to 32bit
  4382. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4383. from->type.intValue = from->type.byteValue;
  4384. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4385. from->type.intValue = from->type.wordValue;
  4386. }
  4387. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4388. {
  4389. // Convert to 32bit
  4390. from->type.intValue = int(from->type.qwordValue);
  4391. }
  4392. else if( from->type.dataType.IsIntegerType() &&
  4393. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4394. {
  4395. // Convert to 32bit
  4396. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4397. from->type.intValue = (signed char)from->type.byteValue;
  4398. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4399. from->type.intValue = (short)from->type.wordValue;
  4400. }
  4401. else if( from->type.dataType.IsEnumType() )
  4402. {
  4403. // Enum type is already an integer type
  4404. }
  4405. // Set the resulting type
  4406. if( to.IsEnumType() )
  4407. from->type.dataType = to;
  4408. else
  4409. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4410. }
  4411. // Check if a downsize is necessary
  4412. if( to.IsIntegerType() &&
  4413. from->type.dataType.IsIntegerType() &&
  4414. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4415. {
  4416. // Verify if it is possible
  4417. if( to.GetSizeInMemoryBytes() == 1 )
  4418. {
  4419. if( char(from->type.intValue) != from->type.intValue )
  4420. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4421. from->type.byteValue = char(from->type.intValue);
  4422. }
  4423. else if( to.GetSizeInMemoryBytes() == 2 )
  4424. {
  4425. if( short(from->type.intValue) != from->type.intValue )
  4426. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4427. from->type.wordValue = short(from->type.intValue);
  4428. }
  4429. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4430. }
  4431. }
  4432. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4433. {
  4434. // Float constants can be implicitly converted to int
  4435. if( from->type.dataType.IsFloatType() )
  4436. {
  4437. float fc = from->type.floatValue;
  4438. asINT64 ic = asINT64(fc);
  4439. if( float(ic) != fc )
  4440. {
  4441. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4442. }
  4443. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4444. from->type.qwordValue = ic;
  4445. }
  4446. // Double constants can be implicitly converted to int
  4447. else if( from->type.dataType.IsDoubleType() )
  4448. {
  4449. double fc = from->type.doubleValue;
  4450. asINT64 ic = asINT64(fc);
  4451. if( double(ic) != fc )
  4452. {
  4453. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4454. }
  4455. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4456. from->type.qwordValue = ic;
  4457. }
  4458. else if( from->type.dataType.IsUnsignedType() )
  4459. {
  4460. // Convert to 64bit
  4461. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4462. from->type.qwordValue = from->type.byteValue;
  4463. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4464. from->type.qwordValue = from->type.wordValue;
  4465. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4466. from->type.qwordValue = from->type.dwordValue;
  4467. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  4468. {
  4469. if( asINT64(from->type.qwordValue) < 0 )
  4470. {
  4471. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4472. }
  4473. }
  4474. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4475. }
  4476. else if( from->type.dataType.IsEnumType() )
  4477. {
  4478. from->type.qwordValue = from->type.intValue;
  4479. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4480. }
  4481. else if( from->type.dataType.IsIntegerType() )
  4482. {
  4483. // Convert to 64bit
  4484. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4485. from->type.qwordValue = (signed char)from->type.byteValue;
  4486. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4487. from->type.qwordValue = (short)from->type.wordValue;
  4488. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4489. from->type.qwordValue = from->type.intValue;
  4490. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4491. }
  4492. }
  4493. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4494. {
  4495. if( from->type.dataType.IsFloatType() )
  4496. {
  4497. float fc = from->type.floatValue;
  4498. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  4499. // To maintain a consistent behaviour across compilers we convert to int first.
  4500. asUINT uic = asUINT(int(fc));
  4501. if( float(uic) != fc )
  4502. {
  4503. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4504. }
  4505. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4506. from->type.intValue = uic;
  4507. // Try once more, in case of a smaller type
  4508. ImplicitConversionConstant(from, to, node, convType);
  4509. }
  4510. else if( from->type.dataType.IsDoubleType() )
  4511. {
  4512. double fc = from->type.doubleValue;
  4513. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  4514. // To maintain a consistent behaviour across compilers we convert to int first.
  4515. asUINT uic = asUINT(int(fc));
  4516. if( double(uic) != fc )
  4517. {
  4518. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4519. }
  4520. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4521. from->type.intValue = uic;
  4522. // Try once more, in case of a smaller type
  4523. ImplicitConversionConstant(from, to, node, convType);
  4524. }
  4525. else if( from->type.dataType.IsEnumType() )
  4526. {
  4527. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4528. // Try once more, in case of a smaller type
  4529. ImplicitConversionConstant(from, to, node, convType);
  4530. }
  4531. else if( from->type.dataType.IsIntegerType() )
  4532. {
  4533. // Verify that it is possible to convert to unsigned without loosing negative
  4534. if( from->type.intValue < 0 )
  4535. {
  4536. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4537. }
  4538. // Convert to 32bit
  4539. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4540. from->type.intValue = (signed char)from->type.byteValue;
  4541. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4542. from->type.intValue = (short)from->type.wordValue;
  4543. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4544. // Try once more, in case of a smaller type
  4545. ImplicitConversionConstant(from, to, node, convType);
  4546. }
  4547. else if( from->type.dataType.IsUnsignedType() &&
  4548. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4549. {
  4550. // Convert to 32bit
  4551. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4552. from->type.dwordValue = from->type.byteValue;
  4553. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4554. from->type.dwordValue = from->type.wordValue;
  4555. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4556. // Try once more, in case of a smaller type
  4557. ImplicitConversionConstant(from, to, node, convType);
  4558. }
  4559. else if( from->type.dataType.IsUnsignedType() &&
  4560. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4561. {
  4562. // Verify if it is possible
  4563. if( to.GetSizeInMemoryBytes() == 1 )
  4564. {
  4565. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  4566. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4567. from->type.byteValue = asBYTE(from->type.dwordValue);
  4568. }
  4569. else if( to.GetSizeInMemoryBytes() == 2 )
  4570. {
  4571. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  4572. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4573. from->type.wordValue = asWORD(from->type.dwordValue);
  4574. }
  4575. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4576. }
  4577. }
  4578. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4579. {
  4580. if( from->type.dataType.IsFloatType() )
  4581. {
  4582. float fc = from->type.floatValue;
  4583. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4584. asQWORD uic = asQWORD(asINT64(fc));
  4585. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4586. // MSVC6 doesn't support this conversion
  4587. if( float(uic) != fc )
  4588. {
  4589. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4590. }
  4591. #endif
  4592. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4593. from->type.qwordValue = uic;
  4594. }
  4595. else if( from->type.dataType.IsDoubleType() )
  4596. {
  4597. double fc = from->type.doubleValue;
  4598. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4599. asQWORD uic = asQWORD(asINT64(fc));
  4600. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4601. // MSVC6 doesn't support this conversion
  4602. if( double(uic) != fc )
  4603. {
  4604. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4605. }
  4606. #endif
  4607. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4608. from->type.qwordValue = uic;
  4609. }
  4610. else if( from->type.dataType.IsEnumType() )
  4611. {
  4612. from->type.qwordValue = (asINT64)from->type.intValue;
  4613. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4614. }
  4615. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4616. {
  4617. // Convert to 64bit
  4618. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4619. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  4620. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4621. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  4622. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4623. from->type.qwordValue = (asINT64)from->type.intValue;
  4624. // Verify that it is possible to convert to unsigned without loosing negative
  4625. if( asINT64(from->type.qwordValue) < 0 )
  4626. {
  4627. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4628. }
  4629. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4630. }
  4631. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4632. {
  4633. // Verify that it is possible to convert to unsigned without loosing negative
  4634. if( asINT64(from->type.qwordValue) < 0 )
  4635. {
  4636. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4637. }
  4638. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4639. }
  4640. else if( from->type.dataType.IsUnsignedType() )
  4641. {
  4642. // Convert to 64bit
  4643. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4644. from->type.qwordValue = from->type.byteValue;
  4645. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4646. from->type.qwordValue = from->type.wordValue;
  4647. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4648. from->type.qwordValue = from->type.dwordValue;
  4649. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4650. }
  4651. }
  4652. else if( to.IsFloatType() )
  4653. {
  4654. if( from->type.dataType.IsDoubleType() )
  4655. {
  4656. double ic = from->type.doubleValue;
  4657. float fc = float(ic);
  4658. // Don't bother warning about this
  4659. // if( double(fc) != ic )
  4660. // {
  4661. // asCString str;
  4662. // str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  4663. // if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str.AddressOf(), node);
  4664. // }
  4665. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4666. from->type.floatValue = fc;
  4667. }
  4668. else if( from->type.dataType.IsEnumType() )
  4669. {
  4670. float fc = float(from->type.intValue);
  4671. if( int(fc) != from->type.intValue )
  4672. {
  4673. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4674. }
  4675. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4676. from->type.floatValue = fc;
  4677. }
  4678. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4679. {
  4680. // Must properly convert value in case the from value is smaller
  4681. int ic;
  4682. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4683. ic = (signed char)from->type.byteValue;
  4684. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4685. ic = (short)from->type.wordValue;
  4686. else
  4687. ic = from->type.intValue;
  4688. float fc = float(ic);
  4689. if( int(fc) != ic )
  4690. {
  4691. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4692. }
  4693. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4694. from->type.floatValue = fc;
  4695. }
  4696. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4697. {
  4698. float fc = float(asINT64(from->type.qwordValue));
  4699. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4700. {
  4701. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4702. }
  4703. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4704. from->type.floatValue = fc;
  4705. }
  4706. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4707. {
  4708. // Must properly convert value in case the from value is smaller
  4709. unsigned int uic;
  4710. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4711. uic = from->type.byteValue;
  4712. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4713. uic = from->type.wordValue;
  4714. else
  4715. uic = from->type.dwordValue;
  4716. float fc = float(uic);
  4717. if( (unsigned int)(fc) != uic )
  4718. {
  4719. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4720. }
  4721. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4722. from->type.floatValue = fc;
  4723. }
  4724. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4725. {
  4726. float fc = float((asINT64)from->type.qwordValue);
  4727. if( asQWORD(fc) != from->type.qwordValue )
  4728. {
  4729. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4730. }
  4731. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4732. from->type.floatValue = fc;
  4733. }
  4734. }
  4735. else if( to.IsDoubleType() )
  4736. {
  4737. if( from->type.dataType.IsFloatType() )
  4738. {
  4739. float ic = from->type.floatValue;
  4740. double fc = double(ic);
  4741. // Don't check for float->double
  4742. // if( float(fc) != ic )
  4743. // {
  4744. // acCString str;
  4745. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  4746. // if( !isExplicit ) Warning(str, node);
  4747. // }
  4748. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4749. from->type.doubleValue = fc;
  4750. }
  4751. else if( from->type.dataType.IsEnumType() )
  4752. {
  4753. double fc = double(from->type.intValue);
  4754. if( int(fc) != from->type.intValue )
  4755. {
  4756. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4757. }
  4758. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4759. from->type.doubleValue = fc;
  4760. }
  4761. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4762. {
  4763. // Must properly convert value in case the from value is smaller
  4764. int ic;
  4765. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4766. ic = (signed char)from->type.byteValue;
  4767. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4768. ic = (short)from->type.wordValue;
  4769. else
  4770. ic = from->type.intValue;
  4771. double fc = double(ic);
  4772. if( int(fc) != ic )
  4773. {
  4774. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4775. }
  4776. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4777. from->type.doubleValue = fc;
  4778. }
  4779. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4780. {
  4781. double fc = double(asINT64(from->type.qwordValue));
  4782. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4783. {
  4784. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4785. }
  4786. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4787. from->type.doubleValue = fc;
  4788. }
  4789. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4790. {
  4791. // Must properly convert value in case the from value is smaller
  4792. unsigned int uic;
  4793. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4794. uic = from->type.byteValue;
  4795. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4796. uic = from->type.wordValue;
  4797. else
  4798. uic = from->type.dwordValue;
  4799. double fc = double(uic);
  4800. if( (unsigned int)(fc) != uic )
  4801. {
  4802. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4803. }
  4804. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4805. from->type.doubleValue = fc;
  4806. }
  4807. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4808. {
  4809. double fc = double((asINT64)from->type.qwordValue);
  4810. if( asQWORD(fc) != from->type.qwordValue )
  4811. {
  4812. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4813. }
  4814. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4815. from->type.doubleValue = fc;
  4816. }
  4817. }
  4818. }
  4819. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  4820. {
  4821. // Implicit handle types should always be treated as handles in assignments
  4822. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4823. {
  4824. lctx->type.dataType.MakeHandle(true);
  4825. lctx->type.isExplicitHandle = true;
  4826. }
  4827. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  4828. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  4829. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle && !lctx->type.dataType.GetBehaviour()->copy)
  4830. lctx->type.isExplicitHandle = true;
  4831. // If the left hand expression is a property accessor, then that should be used
  4832. // to do the assignment instead of the ordinary operator. The exception is when
  4833. // the property accessor is for a handle property, and the operation is a value
  4834. // assignment.
  4835. if( (lctx->property_get || lctx->property_set) &&
  4836. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  4837. {
  4838. if( op != ttAssignment )
  4839. {
  4840. // TODO: getset: We may actually be able to support this, if we can
  4841. // guarantee that the object reference will stay valid
  4842. // between the calls to the get and set accessors.
  4843. // Process the property to free the memory
  4844. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4845. // Compound assignments are not allowed for properties
  4846. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  4847. return -1;
  4848. }
  4849. // It is not allowed to do a handle assignment on a property
  4850. // accessor that doesn't take a handle in the set accessor.
  4851. if( lctx->property_set && lctx->type.isExplicitHandle )
  4852. {
  4853. // set_opIndex has 2 arguments, where as normal setters have only 1
  4854. asCArray<asCDataType>& parameterTypes =
  4855. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  4856. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  4857. {
  4858. // Process the property to free the memory
  4859. ProcessPropertySetAccessor(lctx, rctx, opNode);
  4860. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  4861. return -1;
  4862. }
  4863. }
  4864. MergeExprBytecodeAndType(ctx, lctx);
  4865. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  4866. }
  4867. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4868. {
  4869. // Get the handle to the object that will be used for the value assignment
  4870. ProcessPropertyGetAccessor(lctx, opNode);
  4871. }
  4872. if( lctx->type.dataType.IsPrimitive() )
  4873. {
  4874. if( !lctx->type.isLValue )
  4875. {
  4876. Error(TXT_NOT_LVALUE, lexpr);
  4877. return -1;
  4878. }
  4879. if( op != ttAssignment )
  4880. {
  4881. // Compute the operator before the assignment
  4882. asCTypeInfo lvalue = lctx->type;
  4883. if( lctx->type.isTemporary && !lctx->type.isVariable )
  4884. {
  4885. // The temporary variable must not be freed until the
  4886. // assignment has been performed. lvalue still holds
  4887. // the information about the temporary variable
  4888. lctx->type.isTemporary = false;
  4889. }
  4890. asSExprContext o(engine);
  4891. CompileOperator(opNode, lctx, rctx, &o);
  4892. MergeExprBytecode(rctx, &o);
  4893. rctx->type = o.type;
  4894. // Convert the rvalue to the right type and validate it
  4895. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  4896. MergeExprBytecode(ctx, rctx);
  4897. lctx->type = lvalue;
  4898. // The lvalue continues the same, either it was a variable, or a reference in the register
  4899. }
  4900. else
  4901. {
  4902. // Convert the rvalue to the right type and validate it
  4903. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  4904. MergeExprBytecode(ctx, rctx);
  4905. MergeExprBytecode(ctx, lctx);
  4906. }
  4907. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4908. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4909. ctx->type = lctx->type;
  4910. }
  4911. else if( lctx->type.isExplicitHandle )
  4912. {
  4913. if( !lctx->type.isLValue )
  4914. {
  4915. Error(TXT_NOT_LVALUE, lexpr);
  4916. return -1;
  4917. }
  4918. // Object handles don't have any compound assignment operators
  4919. if( op != ttAssignment )
  4920. {
  4921. asCString str;
  4922. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4923. Error(str.AddressOf(), lexpr);
  4924. return -1;
  4925. }
  4926. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  4927. {
  4928. // The object is a value type but that should be treated as a handle
  4929. // TODO: handle: Make sure the right hand value is a handle
  4930. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4931. {
  4932. // An overloaded assignment operator was found (or a compilation error occured)
  4933. return 0;
  4934. }
  4935. // The object must implement the opAssign method
  4936. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  4937. return -1;
  4938. }
  4939. else
  4940. {
  4941. asCDataType dt = lctx->type.dataType;
  4942. dt.MakeReference(false);
  4943. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4944. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4945. {
  4946. asCString str;
  4947. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4948. Error(str.AddressOf(), rexpr);
  4949. return -1;
  4950. }
  4951. MergeExprBytecode(ctx, rctx);
  4952. MergeExprBytecode(ctx, lctx);
  4953. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4954. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4955. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4956. ctx->type = rctx->type;
  4957. }
  4958. }
  4959. else // if( lctx->type.dataType.IsObject() )
  4960. {
  4961. // An ASHANDLE type must not allow a value assignment, as
  4962. // the opAssign operator is used for the handle assignment
  4963. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  4964. {
  4965. asCString str;
  4966. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4967. Error(str.AddressOf(), lexpr);
  4968. return -1;
  4969. }
  4970. // The lvalue reference may be marked as a temporary, if for example
  4971. // it was originated as a handle returned from a function. In such
  4972. // cases it must be possible to assign values to it anyway.
  4973. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4974. {
  4975. // Convert the handle to a object reference
  4976. asCDataType to;
  4977. to = lctx->type.dataType;
  4978. to.MakeHandle(false);
  4979. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  4980. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  4981. }
  4982. // Check for overloaded assignment operator
  4983. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4984. {
  4985. // An overloaded assignment operator was found (or a compilation error occured)
  4986. return 0;
  4987. }
  4988. // No registered operator was found. In case the operation is a direct
  4989. // assignment and the rvalue is the same type as the lvalue, then we can
  4990. // still use the byte-for-byte copy to do the assignment
  4991. if( op != ttAssignment )
  4992. {
  4993. asCString str;
  4994. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4995. Error(str.AddressOf(), lexpr);
  4996. return -1;
  4997. }
  4998. // If the left hand expression is simple, i.e. without any
  4999. // function calls or allocations of memory, then we can avoid
  5000. // doing a copy of the right hand expression (done by PrepareArgument).
  5001. // Instead the reference to the value can be placed directly on the
  5002. // stack.
  5003. //
  5004. // This optimization should only be done for value types, where
  5005. // the application developer is responsible for making the
  5006. // implementation safe against unwanted destruction of the input
  5007. // reference before the time.
  5008. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  5009. // Implicitly convert the rvalue to the type of the lvalue
  5010. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5011. simpleExpr = false;
  5012. if( !simpleExpr )
  5013. {
  5014. asCDataType dt = lctx->type.dataType;
  5015. dt.MakeReference(true);
  5016. dt.MakeReadOnly(true);
  5017. PrepareArgument(&dt, rctx, rexpr, true, 1);
  5018. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5019. {
  5020. asCString str;
  5021. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5022. Error(str.AddressOf(), rexpr);
  5023. return -1;
  5024. }
  5025. }
  5026. else if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  5027. rctx->bc.Instr(asBC_RDSPTR);
  5028. MergeExprBytecode(ctx, rctx);
  5029. MergeExprBytecode(ctx, lctx);
  5030. if( !simpleExpr )
  5031. {
  5032. if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
  5033. // TODO: optimize: Actually the reference can be pushed on the stack directly
  5034. // as the value allocated on the stack is guaranteed to be safe
  5035. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  5036. else
  5037. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5038. }
  5039. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5040. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5041. ctx->type = lctx->type;
  5042. }
  5043. return 0;
  5044. }
  5045. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  5046. {
  5047. asCScriptNode *lexpr = expr->firstChild;
  5048. if( lexpr->next )
  5049. {
  5050. // Compile the two expression terms
  5051. asSExprContext lctx(engine), rctx(engine);
  5052. int rr = CompileAssignment(lexpr->next->next, &rctx);
  5053. int lr = CompileCondition(lexpr, &lctx);
  5054. if( lr >= 0 && rr >= 0 )
  5055. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  5056. // Since the operands failed, the assignment was not computed
  5057. ctx->type.SetDummy();
  5058. return -1;
  5059. }
  5060. return CompileCondition(lexpr, ctx);
  5061. }
  5062. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  5063. {
  5064. asCTypeInfo ctype;
  5065. // Compile the conditional expression
  5066. asCScriptNode *cexpr = expr->firstChild;
  5067. if( cexpr->next )
  5068. {
  5069. //-------------------------------
  5070. // Compile the condition
  5071. asSExprContext e(engine);
  5072. int r = CompileExpression(cexpr, &e);
  5073. if( r < 0 )
  5074. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5075. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  5076. {
  5077. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  5078. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5079. }
  5080. ctype = e.type;
  5081. ProcessPropertyGetAccessor(&e, cexpr);
  5082. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  5083. ProcessDeferredParams(&e);
  5084. //-------------------------------
  5085. // Compile the left expression
  5086. asSExprContext le(engine);
  5087. int lr = CompileAssignment(cexpr->next, &le);
  5088. //-------------------------------
  5089. // Compile the right expression
  5090. asSExprContext re(engine);
  5091. int rr = CompileAssignment(cexpr->next->next, &re);
  5092. if( lr >= 0 && rr >= 0 )
  5093. {
  5094. ProcessPropertyGetAccessor(&le, cexpr->next);
  5095. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  5096. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  5097. // Allow a 0 or null in the first case to be implicitly converted to the second type
  5098. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  5099. {
  5100. asCDataType to = re.type.dataType;
  5101. to.MakeReference(false);
  5102. to.MakeReadOnly(true);
  5103. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5104. }
  5105. else if( le.type.IsNullConstant() )
  5106. {
  5107. asCDataType to = re.type.dataType;
  5108. to.MakeHandle(true);
  5109. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5110. }
  5111. //---------------------------------
  5112. // Output the byte code
  5113. int afterLabel = nextLabel++;
  5114. int elseLabel = nextLabel++;
  5115. // If left expression is void, then we don't need to store the result
  5116. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  5117. {
  5118. // Put the code for the condition expression on the output
  5119. MergeExprBytecode(ctx, &e);
  5120. // Added the branch decision
  5121. ctx->type = e.type;
  5122. ConvertToVariable(ctx);
  5123. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5124. ctx->bc.Instr(asBC_ClrHi);
  5125. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5126. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5127. // Add the left expression
  5128. MergeExprBytecode(ctx, &le);
  5129. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5130. // Add the right expression
  5131. ctx->bc.Label((short)elseLabel);
  5132. MergeExprBytecode(ctx, &re);
  5133. ctx->bc.Label((short)afterLabel);
  5134. // Make sure both expressions have the same type
  5135. if( le.type.dataType != re.type.dataType )
  5136. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5137. // Set the type of the result
  5138. ctx->type = le.type;
  5139. }
  5140. else
  5141. {
  5142. // Allocate temporary variable and copy the result to that one
  5143. asCTypeInfo temp;
  5144. temp = le.type;
  5145. temp.dataType.MakeReference(false);
  5146. temp.dataType.MakeReadOnly(false);
  5147. // Make sure the variable isn't used in the initial expression
  5148. int offset = AllocateVariableNotIn(temp.dataType, true, false, &e);
  5149. temp.SetVariable(temp.dataType, offset, true);
  5150. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  5151. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  5152. // Put the code for the condition expression on the output
  5153. MergeExprBytecode(ctx, &e);
  5154. // Add the branch decision
  5155. ctx->type = e.type;
  5156. ConvertToVariable(ctx);
  5157. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5158. ctx->bc.Instr(asBC_ClrHi);
  5159. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5160. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5161. // Assign the result of the left expression to the temporary variable
  5162. asCTypeInfo rtemp;
  5163. rtemp = temp;
  5164. if( rtemp.dataType.IsObjectHandle() )
  5165. rtemp.isExplicitHandle = true;
  5166. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  5167. MergeExprBytecode(ctx, &le);
  5168. if( !rtemp.dataType.IsPrimitive() )
  5169. {
  5170. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5171. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5172. }
  5173. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  5174. if( !rtemp.dataType.IsPrimitive() )
  5175. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  5176. // Release the old temporary variable
  5177. ReleaseTemporaryVariable(le.type, &ctx->bc);
  5178. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5179. // Start of the right expression
  5180. ctx->bc.Label((short)elseLabel);
  5181. // Copy the result to the same temporary variable
  5182. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  5183. MergeExprBytecode(ctx, &re);
  5184. if( !rtemp.dataType.IsPrimitive() )
  5185. {
  5186. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5187. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5188. }
  5189. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  5190. if( !rtemp.dataType.IsPrimitive() )
  5191. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  5192. // Release the old temporary variable
  5193. ReleaseTemporaryVariable(re.type, &ctx->bc);
  5194. ctx->bc.Label((short)afterLabel);
  5195. // Make sure both expressions have the same type
  5196. if( le.type.dataType != re.type.dataType )
  5197. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5198. // Set the temporary variable as output
  5199. ctx->type = rtemp;
  5200. ctx->type.isExplicitHandle = isExplicitHandle;
  5201. if( !ctx->type.dataType.IsPrimitive() )
  5202. {
  5203. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5204. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  5205. }
  5206. // Make sure the output isn't marked as being a literal constant
  5207. ctx->type.isConstant = false;
  5208. }
  5209. }
  5210. else
  5211. {
  5212. ctx->type.SetDummy();
  5213. return -1;
  5214. }
  5215. }
  5216. else
  5217. return CompileExpression(cexpr, ctx);
  5218. return 0;
  5219. }
  5220. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  5221. {
  5222. asASSERT(expr->nodeType == snExpression);
  5223. // Count the nodes
  5224. int count = 0;
  5225. asCScriptNode *node = expr->firstChild;
  5226. while( node )
  5227. {
  5228. count++;
  5229. node = node->next;
  5230. }
  5231. // Convert to polish post fix, i.e: a+b => ab+
  5232. asCArray<asCScriptNode *> stack(count);
  5233. asCArray<asCScriptNode *> stack2(count);
  5234. asCArray<asCScriptNode *> postfix(count);
  5235. node = expr->firstChild;
  5236. while( node )
  5237. {
  5238. int precedence = GetPrecedence(node);
  5239. while( stack.GetLength() > 0 &&
  5240. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  5241. stack2.PushLast(stack.PopLast());
  5242. stack.PushLast(node);
  5243. node = node->next;
  5244. }
  5245. while( stack.GetLength() > 0 )
  5246. stack2.PushLast(stack.PopLast());
  5247. // We need to swap operands so that the left
  5248. // operand is always computed before the right
  5249. SwapPostFixOperands(stack2, postfix);
  5250. // Compile the postfix formatted expression
  5251. return CompilePostFixExpression(&postfix, ctx);
  5252. }
  5253. void asCCompiler::SwapPostFixOperands(asCArray<asCScriptNode *> &postfix, asCArray<asCScriptNode *> &target)
  5254. {
  5255. if( postfix.GetLength() == 0 ) return;
  5256. asCScriptNode *node = postfix.PopLast();
  5257. if( node->nodeType == snExprTerm )
  5258. {
  5259. target.PushLast(node);
  5260. return;
  5261. }
  5262. SwapPostFixOperands(postfix, target);
  5263. SwapPostFixOperands(postfix, target);
  5264. target.PushLast(node);
  5265. }
  5266. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  5267. {
  5268. // Shouldn't send any byte code
  5269. asASSERT(ctx->bc.GetLastInstr() == -1);
  5270. // Set the context to a dummy type to avoid further
  5271. // errors in case the expression fails to compile
  5272. ctx->type.SetDummy();
  5273. // Pop the last node
  5274. asCScriptNode *node = postfix->PopLast();
  5275. ctx->exprNode = node;
  5276. // If term, compile the term
  5277. if( node->nodeType == snExprTerm )
  5278. return CompileExpressionTerm(node, ctx);
  5279. // Compile the two expression terms
  5280. asSExprContext r(engine), l(engine);
  5281. int ret;
  5282. ret = CompilePostFixExpression(postfix, &l); if( ret < 0 ) return ret;
  5283. ret = CompilePostFixExpression(postfix, &r); if( ret < 0 ) return ret;
  5284. // Compile the operation
  5285. return CompileOperator(node, &l, &r, ctx);
  5286. }
  5287. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  5288. {
  5289. // Shouldn't send any byte code
  5290. asASSERT(ctx->bc.GetLastInstr() == -1);
  5291. // Set the type as a dummy by default, in case of any compiler errors
  5292. ctx->type.SetDummy();
  5293. // Compile the value node
  5294. asCScriptNode *vnode = node->firstChild;
  5295. while( vnode->nodeType != snExprValue )
  5296. vnode = vnode->next;
  5297. asSExprContext v(engine);
  5298. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  5299. // Compile post fix operators
  5300. asCScriptNode *pnode = vnode->next;
  5301. while( pnode )
  5302. {
  5303. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  5304. pnode = pnode->next;
  5305. }
  5306. // Compile pre fix operators
  5307. pnode = vnode->prev;
  5308. while( pnode )
  5309. {
  5310. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  5311. pnode = pnode->prev;
  5312. }
  5313. // Return the byte code and final type description
  5314. MergeExprBytecodeAndType(ctx, &v);
  5315. return 0;
  5316. }
  5317. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, asCObjectType *objType)
  5318. {
  5319. bool found = false;
  5320. // It is a local variable or parameter?
  5321. // This is not accessible by default arg expressions
  5322. sVariable *v = 0;
  5323. if( !isCompilingDefaultArg && scope == "" && !objType )
  5324. v = variables->GetVariable(name.AddressOf());
  5325. if( v )
  5326. {
  5327. found = true;
  5328. if( v->isPureConstant )
  5329. ctx->type.SetConstantQW(v->type, v->constantValue);
  5330. else if( v->type.IsPrimitive() )
  5331. {
  5332. if( v->type.IsReference() )
  5333. {
  5334. // Copy the reference into the register
  5335. #if AS_PTR_SIZE == 1
  5336. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)v->stackOffset);
  5337. #else
  5338. ctx->bc.InstrSHORT(asBC_CpyVtoR8, (short)v->stackOffset);
  5339. #endif
  5340. ctx->type.Set(v->type);
  5341. }
  5342. else
  5343. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5344. ctx->type.isLValue = true;
  5345. }
  5346. else
  5347. {
  5348. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  5349. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5350. // If the variable is allocated on the heap we have a reference,
  5351. // otherwise the actual object pointer is pushed on the stack.
  5352. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  5353. // Implicitly dereference handle parameters sent by reference
  5354. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  5355. ctx->bc.Instr(asBC_RDSPTR);
  5356. ctx->type.isLValue = true;
  5357. }
  5358. }
  5359. // Is it a class member?
  5360. // This is not accessible by default arg expressions
  5361. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  5362. {
  5363. if( name == THIS_TOKEN && !objType )
  5364. {
  5365. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  5366. // The object pointer is located at stack position 0
  5367. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5368. ctx->type.SetVariable(dt, 0, false);
  5369. ctx->type.dataType.MakeReference(true);
  5370. ctx->type.isLValue = true;
  5371. found = true;
  5372. }
  5373. if( !found )
  5374. {
  5375. // See if there are any matching property accessors
  5376. asSExprContext access(engine);
  5377. if( objType )
  5378. access.type.Set(asCDataType::CreateObject(objType, false));
  5379. else
  5380. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  5381. access.type.dataType.MakeReference(true);
  5382. int r = 0;
  5383. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5384. {
  5385. // This is an index access, check if there is a property accessor that takes an index arg
  5386. asSExprContext dummyArg(engine);
  5387. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, true);
  5388. }
  5389. if( r == 0 )
  5390. {
  5391. // Normal property access
  5392. r = FindPropertyAccessor(name, &access, errNode, true);
  5393. }
  5394. if( r < 0 ) return -1;
  5395. if( access.property_get || access.property_set )
  5396. {
  5397. if( !objType )
  5398. {
  5399. // Prepare the bytecode for the member access
  5400. // This is only done when accessing through the implicit this pointer
  5401. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5402. }
  5403. MergeExprBytecodeAndType(ctx, &access);
  5404. found = true;
  5405. }
  5406. }
  5407. if( !found )
  5408. {
  5409. asCDataType dt;
  5410. if( objType )
  5411. dt = asCDataType::CreateObject(objType, false);
  5412. else
  5413. dt = asCDataType::CreateObject(outFunc->objectType, false);
  5414. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  5415. if( prop )
  5416. {
  5417. if( !objType )
  5418. {
  5419. // The object pointer is located at stack position 0
  5420. // This is only done when accessing through the implicit this pointer
  5421. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5422. ctx->type.SetVariable(dt, 0, false);
  5423. ctx->type.dataType.MakeReference(true);
  5424. Dereference(ctx, true);
  5425. }
  5426. // TODO: This is the same as what is in CompileExpressionPostOp
  5427. // Put the offset on the stack
  5428. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  5429. if( prop->type.IsReference() )
  5430. ctx->bc.Instr(asBC_RDSPTR);
  5431. // Reference to primitive must be stored in the temp register
  5432. if( prop->type.IsPrimitive() )
  5433. {
  5434. // TODO: optimize: The ADD offset command should store the reference in the register directly
  5435. ctx->bc.Instr(asBC_PopRPtr);
  5436. }
  5437. // Set the new type (keeping info about temp variable)
  5438. ctx->type.dataType = prop->type;
  5439. ctx->type.dataType.MakeReference(true);
  5440. ctx->type.isVariable = false;
  5441. ctx->type.isLValue = true;
  5442. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  5443. {
  5444. // Objects that are members are not references
  5445. ctx->type.dataType.MakeReference(false);
  5446. }
  5447. // If the object reference is const, the property will also be const
  5448. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  5449. found = true;
  5450. }
  5451. }
  5452. }
  5453. // Is it a global property?
  5454. if( !found && (scope == "" || scope == "::") && !objType )
  5455. {
  5456. // See if there are any matching global property accessors
  5457. asSExprContext access(engine);
  5458. int r = 0;
  5459. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5460. {
  5461. // This is an index access, check if there is a property accessor that takes an index arg
  5462. asSExprContext dummyArg(engine);
  5463. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  5464. }
  5465. if( r == 0 )
  5466. {
  5467. // Normal property access
  5468. r = FindPropertyAccessor(name, &access, errNode);
  5469. }
  5470. if( r < 0 ) return -1;
  5471. if( access.property_get || access.property_set )
  5472. {
  5473. // Prepare the bytecode for the function call
  5474. MergeExprBytecodeAndType(ctx, &access);
  5475. found = true;
  5476. }
  5477. // See if there is any matching global property
  5478. if( !found )
  5479. {
  5480. bool isCompiled = true;
  5481. bool isPureConstant = false;
  5482. bool isAppProp = false;
  5483. asQWORD constantValue;
  5484. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  5485. if( prop )
  5486. {
  5487. found = true;
  5488. // Verify that the global property has been compiled already
  5489. if( isCompiled )
  5490. {
  5491. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5492. {
  5493. ctx->type.dataType.MakeHandle(true);
  5494. ctx->type.isExplicitHandle = true;
  5495. }
  5496. // If the global property is a pure constant
  5497. // we can allow the compiler to optimize it. Pure
  5498. // constants are global constant variables that were
  5499. // initialized by literal constants.
  5500. if( isPureConstant )
  5501. ctx->type.SetConstantQW(prop->type, constantValue);
  5502. else
  5503. {
  5504. // A shared type must not access global vars, unless they
  5505. // too are shared, e.g. application registered vars
  5506. if( outFunc->objectType && outFunc->objectType->IsShared() )
  5507. {
  5508. if( !isAppProp )
  5509. {
  5510. asCString str;
  5511. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  5512. Error(str.AddressOf(), errNode);
  5513. // Allow the compilation to continue to catch other problems
  5514. }
  5515. }
  5516. ctx->type.Set(prop->type);
  5517. ctx->type.dataType.MakeReference(true);
  5518. ctx->type.isLValue = true;
  5519. if( ctx->type.dataType.IsPrimitive() )
  5520. {
  5521. // Load the address of the variable into the register
  5522. ctx->bc.InstrPTR(asBC_LDG, engine->globalProperties[prop->id]->GetAddressOfValue());
  5523. }
  5524. else
  5525. {
  5526. // Push the address of the variable on the stack
  5527. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[prop->id]->GetAddressOfValue());
  5528. // If the object is a value type, then we must validate the existance,
  5529. // as it could potentially be accessed before it is initialized.
  5530. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
  5531. !ctx->type.dataType.IsObjectHandle() )
  5532. {
  5533. // TODO: optimize: This is not necessary for application registered properties
  5534. ctx->bc.Instr(asBC_ChkRefS);
  5535. }
  5536. }
  5537. }
  5538. }
  5539. else
  5540. {
  5541. asCString str;
  5542. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  5543. Error(str.AddressOf(), errNode);
  5544. return -1;
  5545. }
  5546. }
  5547. }
  5548. }
  5549. // Is it the name of a global function?
  5550. if( !noFunction && !found && (scope == "" || scope == "::") && !objType )
  5551. {
  5552. asCArray<int> funcs;
  5553. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  5554. if( funcs.GetLength() > 1 )
  5555. {
  5556. // TODO: funcdef: If multiple functions are found, then the compiler should defer the decision
  5557. // to which one it should use until the value is actually used.
  5558. //
  5559. // - assigning the function pointer to a variable
  5560. // - performing an explicit cast
  5561. // - passing the function pointer to a function as parameter
  5562. asCString str;
  5563. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, name.AddressOf());
  5564. Error(str.AddressOf(), errNode);
  5565. return -1;
  5566. }
  5567. else if( funcs.GetLength() == 1 )
  5568. {
  5569. found = true;
  5570. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  5571. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  5572. outFunc->objectType && outFunc->objectType->IsShared() )
  5573. {
  5574. asCString msg;
  5575. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  5576. Error(msg.AddressOf(), errNode);
  5577. return -1;
  5578. }
  5579. // Push the function pointer on the stack
  5580. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  5581. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  5582. }
  5583. }
  5584. // Is it an enum value?
  5585. if( !found && !objType )
  5586. {
  5587. asCObjectType *scopeType = 0;
  5588. if( scope != "" )
  5589. {
  5590. // resolve the type before the scope
  5591. scopeType = builder->GetObjectType( scope.AddressOf() );
  5592. }
  5593. asDWORD value = 0;
  5594. asCDataType dt;
  5595. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  5596. {
  5597. // scoped enum value found
  5598. found = true;
  5599. }
  5600. else if( scope == "" && !engine->ep.requireEnumScope )
  5601. {
  5602. // look for the enum value with no namespace
  5603. int e = builder->GetEnumValue(name.AddressOf(), dt, value);
  5604. if( e )
  5605. {
  5606. found = true;
  5607. if( e == 2 )
  5608. {
  5609. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  5610. }
  5611. }
  5612. }
  5613. if( found )
  5614. {
  5615. // Even if the enum type is not shared, and we're compiling a shared object,
  5616. // the use of the values are still allowed, since they are treated as constants.
  5617. // an enum value was resolved
  5618. ctx->type.SetConstantDW(dt, value);
  5619. }
  5620. }
  5621. // The name doesn't match any variable
  5622. if( !found )
  5623. {
  5624. // Give dummy value
  5625. ctx->type.SetDummy();
  5626. if( !isOptional )
  5627. {
  5628. // Prepend the scope to the name for the error message
  5629. asCString ename;
  5630. if( scope != "" && scope != "::" )
  5631. ename = scope + "::";
  5632. else
  5633. ename = scope;
  5634. ename += name;
  5635. asCString str;
  5636. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  5637. Error(str.AddressOf(), errNode);
  5638. // Declare the variable now so that it will not be reported again
  5639. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  5640. // Mark the variable as initialized so that the user will not be bother by it again
  5641. sVariable *v = variables->GetVariable(name.AddressOf());
  5642. asASSERT(v);
  5643. if( v ) v->isInitialized = true;
  5644. }
  5645. // Return -1 to signal that the variable wasn't found
  5646. return -1;
  5647. }
  5648. return 0;
  5649. }
  5650. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  5651. {
  5652. // Shouldn't receive any byte code
  5653. asASSERT(ctx->bc.GetLastInstr() == -1);
  5654. asCScriptNode *vnode = node->firstChild;
  5655. ctx->exprNode = vnode;
  5656. if( vnode->nodeType == snVariableAccess )
  5657. {
  5658. // Determine the scope resolution of the variable
  5659. asCString scope = GetScopeFromNode(vnode);
  5660. // Determine the name of the variable
  5661. vnode = vnode->lastChild;
  5662. asASSERT(vnode->nodeType == snIdentifier );
  5663. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  5664. return CompileVariableAccess(name, scope, ctx, node);
  5665. }
  5666. else if( vnode->nodeType == snConstant )
  5667. {
  5668. if( vnode->tokenType == ttIntConstant )
  5669. {
  5670. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5671. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  5672. // Do we need 64 bits?
  5673. if( val>>32 )
  5674. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5675. else
  5676. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5677. }
  5678. else if( vnode->tokenType == ttBitsConstant )
  5679. {
  5680. asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
  5681. // TODO: Check for overflow
  5682. asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
  5683. // Do we need 64 bits?
  5684. if( val>>32 )
  5685. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5686. else
  5687. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5688. }
  5689. else if( vnode->tokenType == ttFloatConstant )
  5690. {
  5691. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5692. // TODO: Check for overflow
  5693. size_t numScanned;
  5694. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  5695. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  5696. #ifndef AS_USE_DOUBLE_AS_FLOAT
  5697. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  5698. asASSERT(numScanned == vnode->tokenLength - 1);
  5699. #endif
  5700. }
  5701. else if( vnode->tokenType == ttDoubleConstant )
  5702. {
  5703. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5704. // TODO: Check for overflow
  5705. size_t numScanned;
  5706. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  5707. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  5708. asASSERT(numScanned == vnode->tokenLength);
  5709. }
  5710. else if( vnode->tokenType == ttTrue ||
  5711. vnode->tokenType == ttFalse )
  5712. {
  5713. #if AS_SIZEOF_BOOL == 1
  5714. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5715. #else
  5716. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5717. #endif
  5718. }
  5719. else if( vnode->tokenType == ttStringConstant ||
  5720. vnode->tokenType == ttMultilineStringConstant ||
  5721. vnode->tokenType == ttHeredocStringConstant )
  5722. {
  5723. asCString str;
  5724. asCScriptNode *snode = vnode->firstChild;
  5725. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  5726. {
  5727. // Treat the single quoted string as a single character literal
  5728. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5729. asDWORD val = 0;
  5730. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  5731. {
  5732. // This is the start of a UTF8 encoded character. We need to decode it
  5733. val = asStringDecodeUTF8(str.AddressOf(), 0);
  5734. if( val == (asDWORD)-1 )
  5735. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5736. }
  5737. else
  5738. {
  5739. val = ProcessStringConstant(str, snode);
  5740. if( val == (asDWORD)-1 )
  5741. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5742. }
  5743. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  5744. }
  5745. else
  5746. {
  5747. // Process the string constants
  5748. while( snode )
  5749. {
  5750. asCString cat;
  5751. if( snode->tokenType == ttStringConstant )
  5752. {
  5753. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5754. ProcessStringConstant(cat, snode);
  5755. }
  5756. else if( snode->tokenType == ttMultilineStringConstant )
  5757. {
  5758. if( !engine->ep.allowMultilineStrings )
  5759. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  5760. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5761. ProcessStringConstant(cat, snode);
  5762. }
  5763. else if( snode->tokenType == ttHeredocStringConstant )
  5764. {
  5765. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  5766. ProcessHeredocStringConstant(cat, snode);
  5767. }
  5768. str += cat;
  5769. snode = snode->next;
  5770. }
  5771. // Call the string factory function to create a string object
  5772. asCScriptFunction *descr = engine->stringFactory;
  5773. if( descr == 0 )
  5774. {
  5775. // Error
  5776. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  5777. // Give dummy value
  5778. ctx->type.SetDummy();
  5779. return -1;
  5780. }
  5781. else
  5782. {
  5783. // Register the constant string with the engine
  5784. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  5785. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  5786. bool useVariable = false;
  5787. int stackOffset = 0;
  5788. #ifndef AS_OLD
  5789. if( descr->DoesReturnOnStack() )
  5790. {
  5791. useVariable = true;
  5792. stackOffset = AllocateVariable(descr->returnType, true);
  5793. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5794. }
  5795. #endif
  5796. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  5797. }
  5798. }
  5799. }
  5800. else if( vnode->tokenType == ttNull )
  5801. {
  5802. #ifndef AS_64BIT_PTR
  5803. ctx->bc.InstrDWORD(asBC_PshC4, 0);
  5804. #else
  5805. ctx->bc.InstrQWORD(asBC_PshC8, 0);
  5806. #endif
  5807. ctx->type.SetNullConstant();
  5808. }
  5809. else
  5810. asASSERT(false);
  5811. }
  5812. else if( vnode->nodeType == snFunctionCall )
  5813. {
  5814. // Determine the scope resolution
  5815. asCString scope = GetScopeFromNode(vnode);
  5816. if( outFunc && outFunc->objectType && scope != "::" )
  5817. {
  5818. // TODO: funcdef: There may be a local variable of a function type with the same name
  5819. // Check if a class method is being called
  5820. asCScriptNode *nm = vnode->lastChild->prev;
  5821. asCString name;
  5822. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  5823. asCArray<int> funcs;
  5824. // If we're compiling a constructor and the name of the function called
  5825. // is 'super' then the base class' constructor is being called.
  5826. // super cannot be called from another scope, i.e. must not be prefixed
  5827. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  5828. {
  5829. // Actually it is the base class' constructor that is being called,
  5830. // but as we won't use the actual function ids here we can take the
  5831. // object's own constructors and avoid the need to check if the
  5832. // object actually derives from any other class
  5833. funcs = outFunc->objectType->beh.constructors;
  5834. // Must not allow calling constructors multiple times
  5835. if( continueLabels.GetLength() > 0 )
  5836. {
  5837. // If a continue label is set we are in a loop
  5838. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, vnode);
  5839. }
  5840. else if( breakLabels.GetLength() > 0 )
  5841. {
  5842. // TODO: inheritance: Should eventually allow constructors in switch statements
  5843. // If a break label is set we are either in a loop or a switch statements
  5844. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, vnode);
  5845. }
  5846. else if( m_isConstructorCalled )
  5847. {
  5848. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, vnode);
  5849. }
  5850. m_isConstructorCalled = true;
  5851. }
  5852. else
  5853. builder->GetObjectMethodDescriptions(name.AddressOf(), outFunc->objectType, funcs, false);
  5854. if( funcs.GetLength() )
  5855. {
  5856. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, false);
  5857. // The object pointer is located at stack position 0
  5858. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5859. ctx->type.SetVariable(dt, 0, false);
  5860. ctx->type.dataType.MakeReference(true);
  5861. // TODO: optimize: This adds a CHKREF. Is that really necessary?
  5862. Dereference(ctx, true);
  5863. return CompileFunctionCall(vnode, ctx, outFunc->objectType, false, scope);
  5864. }
  5865. }
  5866. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  5867. }
  5868. else if( vnode->nodeType == snConstructCall )
  5869. {
  5870. CompileConstructCall(vnode, ctx);
  5871. }
  5872. else if( vnode->nodeType == snAssignment )
  5873. {
  5874. asSExprContext e(engine);
  5875. int r = CompileAssignment(vnode, &e);
  5876. if( r < 0 )
  5877. {
  5878. ctx->type.SetDummy();
  5879. return r;
  5880. }
  5881. MergeExprBytecodeAndType(ctx, &e);
  5882. }
  5883. else if( vnode->nodeType == snCast )
  5884. {
  5885. // Implement the cast operator
  5886. CompileConversion(vnode, ctx);
  5887. }
  5888. else
  5889. asASSERT(false);
  5890. return 0;
  5891. }
  5892. asCString asCCompiler::GetScopeFromNode(asCScriptNode *node)
  5893. {
  5894. asCString scope;
  5895. asCScriptNode *sn = node->firstChild;
  5896. if( sn->tokenType == ttScope )
  5897. {
  5898. // Global scope
  5899. scope = "::";
  5900. sn = sn->next;
  5901. }
  5902. else if( sn->next && sn->next->tokenType == ttScope )
  5903. {
  5904. scope.Assign(&script->code[sn->tokenPos], sn->tokenLength);
  5905. sn = sn->next->next;
  5906. }
  5907. if( scope != "" )
  5908. {
  5909. // We don't support multiple levels of scope yet
  5910. if( sn->next && sn->next->tokenType == ttScope )
  5911. {
  5912. Error(TXT_INVALID_SCOPE, sn->next);
  5913. }
  5914. }
  5915. return scope;
  5916. }
  5917. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  5918. {
  5919. int charLiteral = -1;
  5920. // Process escape sequences
  5921. asCArray<char> str((int)cstr.GetLength());
  5922. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  5923. {
  5924. #ifdef AS_DOUBLEBYTE_CHARSET
  5925. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  5926. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  5927. {
  5928. // This is the lead character of a double byte character
  5929. // include the trail character without checking it's value.
  5930. str.PushLast(cstr[n]);
  5931. n++;
  5932. str.PushLast(cstr[n]);
  5933. continue;
  5934. }
  5935. #endif
  5936. asUINT val;
  5937. if( processEscapeSequences && cstr[n] == '\\' )
  5938. {
  5939. ++n;
  5940. if( n == cstr.GetLength() )
  5941. {
  5942. if( charLiteral == -1 ) charLiteral = 0;
  5943. return charLiteral;
  5944. }
  5945. // TODO: Consider deprecating use of hexadecimal escape sequences,
  5946. // as they do not guarantee proper unicode sequences
  5947. if( cstr[n] == 'x' || cstr[n] == 'X' )
  5948. {
  5949. ++n;
  5950. if( n == cstr.GetLength() ) break;
  5951. val = 0;
  5952. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  5953. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  5954. {
  5955. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5956. val = val*16 + cstr[n] - '0';
  5957. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5958. val = val*16 + cstr[n] - 'a' + 10;
  5959. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5960. val = val*16 + cstr[n] - 'A' + 10;
  5961. else
  5962. break;
  5963. }
  5964. // Rewind one, since the loop will increment it again
  5965. n--;
  5966. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  5967. if( engine->ep.stringEncoding == 0 )
  5968. {
  5969. str.PushLast((asBYTE)val);
  5970. }
  5971. else
  5972. {
  5973. #ifndef AS_BIG_ENDIAN
  5974. str.PushLast((asBYTE)val);
  5975. str.PushLast((asBYTE)(val>>8));
  5976. #else
  5977. str.PushLast((asBYTE)(val>>8));
  5978. str.PushLast((asBYTE)val);
  5979. #endif
  5980. }
  5981. if( charLiteral == -1 ) charLiteral = val;
  5982. continue;
  5983. }
  5984. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  5985. {
  5986. // \u expects 4 hex digits
  5987. // \U expects 8 hex digits
  5988. bool expect2 = cstr[n] == 'u';
  5989. int c = expect2 ? 4 : 8;
  5990. val = 0;
  5991. for( ; c > 0; c-- )
  5992. {
  5993. ++n;
  5994. if( n == cstr.GetLength() ) break;
  5995. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5996. val = val*16 + cstr[n] - '0';
  5997. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5998. val = val*16 + cstr[n] - 'a' + 10;
  5999. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6000. val = val*16 + cstr[n] - 'A' + 10;
  6001. else
  6002. break;
  6003. }
  6004. if( c != 0 )
  6005. {
  6006. // Give warning about invalid code point
  6007. // TODO: Need code position for warning
  6008. asCString msg;
  6009. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  6010. Warning(msg.AddressOf(), node);
  6011. continue;
  6012. }
  6013. }
  6014. else
  6015. {
  6016. if( cstr[n] == '"' )
  6017. val = '"';
  6018. else if( cstr[n] == '\'' )
  6019. val = '\'';
  6020. else if( cstr[n] == 'n' )
  6021. val = '\n';
  6022. else if( cstr[n] == 'r' )
  6023. val = '\r';
  6024. else if( cstr[n] == 't' )
  6025. val = '\t';
  6026. else if( cstr[n] == '0' )
  6027. val = '\0';
  6028. else if( cstr[n] == '\\' )
  6029. val = '\\';
  6030. else
  6031. {
  6032. // Invalid escape sequence
  6033. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  6034. continue;
  6035. }
  6036. }
  6037. }
  6038. else
  6039. {
  6040. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  6041. {
  6042. unsigned int len;
  6043. val = asStringDecodeUTF8(&cstr[n], &len);
  6044. if( val == 0xFFFFFFFF )
  6045. {
  6046. // Incorrect UTF8 encoding. Use only the first byte
  6047. // TODO: Need code position for warning
  6048. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  6049. val = (unsigned char)cstr[n];
  6050. }
  6051. else
  6052. n += len-1;
  6053. }
  6054. else
  6055. val = (unsigned char)cstr[n];
  6056. }
  6057. // Add the character to the final string
  6058. char encodedValue[5];
  6059. int len;
  6060. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  6061. {
  6062. // Convert to UTF8 encoded
  6063. len = asStringEncodeUTF8(val, encodedValue);
  6064. }
  6065. else if( engine->ep.stringEncoding == 1 )
  6066. {
  6067. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  6068. len = asStringEncodeUTF16(val, encodedValue);
  6069. }
  6070. else
  6071. {
  6072. // Do not convert ASCII characters
  6073. encodedValue[0] = (asBYTE)val;
  6074. len = 1;
  6075. }
  6076. if( len < 0 )
  6077. {
  6078. // Give warning about invalid code point
  6079. // TODO: Need code position for warning
  6080. Warning(TXT_INVALID_UNICODE_VALUE, node);
  6081. }
  6082. else
  6083. {
  6084. // Add the encoded value to the final string
  6085. str.Concatenate(encodedValue, len);
  6086. if( charLiteral == -1 ) charLiteral = val;
  6087. }
  6088. }
  6089. cstr.Assign(str.AddressOf(), str.GetLength());
  6090. return charLiteral;
  6091. }
  6092. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  6093. {
  6094. // Remove first line if it only contains whitespace
  6095. int start;
  6096. for( start = 0; start < (int)str.GetLength(); start++ )
  6097. {
  6098. if( str[start] == '\n' )
  6099. {
  6100. // Remove the linebreak as well
  6101. start++;
  6102. break;
  6103. }
  6104. if( str[start] != ' ' &&
  6105. str[start] != '\t' &&
  6106. str[start] != '\r' )
  6107. {
  6108. // Don't remove anything
  6109. start = 0;
  6110. break;
  6111. }
  6112. }
  6113. // Remove last line break and the line after that if it only contains whitespaces
  6114. int end;
  6115. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  6116. {
  6117. if( str[end] == '\n' )
  6118. break;
  6119. if( str[end] != ' ' &&
  6120. str[end] != '\t' &&
  6121. str[end] != '\r' )
  6122. {
  6123. // Don't remove anything
  6124. end = (int)str.GetLength();
  6125. break;
  6126. }
  6127. }
  6128. if( end < 0 ) end = 0;
  6129. asCString tmp;
  6130. if( end > start )
  6131. tmp.Assign(&str[start], end-start);
  6132. ProcessStringConstant(tmp, node, false);
  6133. str = tmp;
  6134. }
  6135. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  6136. {
  6137. asSExprContext expr(engine);
  6138. asCDataType to;
  6139. bool anyErrors = false;
  6140. EImplicitConv convType;
  6141. if( node->nodeType == snConstructCall )
  6142. {
  6143. convType = asIC_EXPLICIT_VAL_CAST;
  6144. // Verify that there is only one argument
  6145. if( node->lastChild->firstChild == 0 ||
  6146. node->lastChild->firstChild != node->lastChild->lastChild )
  6147. {
  6148. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  6149. expr.type.SetDummy();
  6150. anyErrors = true;
  6151. }
  6152. else
  6153. {
  6154. // Compile the expression
  6155. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  6156. if( r < 0 )
  6157. anyErrors = true;
  6158. }
  6159. // Determine the requested type
  6160. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  6161. to.MakeReadOnly(true); // Default to const
  6162. asASSERT(to.IsPrimitive());
  6163. }
  6164. else
  6165. {
  6166. convType = asIC_EXPLICIT_REF_CAST;
  6167. // Compile the expression
  6168. int r = CompileAssignment(node->lastChild, &expr);
  6169. if( r < 0 )
  6170. anyErrors = true;
  6171. // Determine the requested type
  6172. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  6173. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  6174. // If the type support object handles, then use it
  6175. if( to.SupportHandles() )
  6176. {
  6177. to.MakeHandle(true);
  6178. }
  6179. else if( !to.IsObjectHandle() )
  6180. {
  6181. // The cast<type> operator can only be used for reference casts
  6182. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  6183. anyErrors = true;
  6184. }
  6185. }
  6186. // Do not allow casting to non shared type if we're compiling a shared method
  6187. if( outFunc->objectType && outFunc->objectType->IsShared() &&
  6188. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  6189. {
  6190. asCString msg;
  6191. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  6192. Error(msg.AddressOf(), node);
  6193. anyErrors = true;
  6194. }
  6195. if( anyErrors )
  6196. {
  6197. // Assume that the error can be fixed and allow the compilation to continue
  6198. ctx->type.SetConstantDW(to, 0);
  6199. return;
  6200. }
  6201. ProcessPropertyGetAccessor(&expr, node);
  6202. // We don't want a reference
  6203. if( expr.type.dataType.IsReference() )
  6204. {
  6205. if( expr.type.dataType.IsObject() )
  6206. Dereference(&expr, true);
  6207. else
  6208. ConvertToVariable(&expr);
  6209. }
  6210. ImplicitConversion(&expr, to, node, convType);
  6211. IsVariableInitialized(&expr.type, node);
  6212. // If no type conversion is really tried ignore it
  6213. if( to == expr.type.dataType )
  6214. {
  6215. // This will keep information about constant type
  6216. MergeExprBytecode(ctx, &expr);
  6217. ctx->type = expr.type;
  6218. return;
  6219. }
  6220. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  6221. {
  6222. MergeExprBytecode(ctx, &expr);
  6223. ctx->type = expr.type;
  6224. ctx->type.dataType.MakeReadOnly(true);
  6225. return;
  6226. }
  6227. // The implicit conversion already does most of the conversions permitted,
  6228. // here we'll only treat those conversions that require an explicit cast.
  6229. bool conversionOK = false;
  6230. if( !expr.type.isConstant )
  6231. {
  6232. if( !expr.type.dataType.IsObject() )
  6233. ConvertToTempVariable(&expr);
  6234. if( to.IsObjectHandle() &&
  6235. expr.type.dataType.IsObjectHandle() &&
  6236. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  6237. {
  6238. conversionOK = CompileRefCast(&expr, to, true, node);
  6239. MergeExprBytecode(ctx, &expr);
  6240. ctx->type = expr.type;
  6241. }
  6242. }
  6243. if( conversionOK )
  6244. return;
  6245. // Conversion not available
  6246. ctx->type.SetDummy();
  6247. asCString strTo, strFrom;
  6248. strTo = to.Format();
  6249. strFrom = expr.type.dataType.Format();
  6250. asCString msg;
  6251. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  6252. Error(msg.AddressOf(), node);
  6253. }
  6254. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  6255. {
  6256. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  6257. // Parameters that are sent by reference should be assigned
  6258. // to the evaluated expression if it is an lvalue
  6259. // Evaluate the arguments from last to first
  6260. int n = (int)descr->parameterTypes.GetLength() - 1;
  6261. for( ; n >= 0; n-- )
  6262. {
  6263. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  6264. (descr->parameterTypes[n].IsObject() && deferAll) )
  6265. {
  6266. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  6267. // For &inout, only store the argument if it is for a temporary variable
  6268. if( engine->ep.allowUnsafeReferences ||
  6269. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  6270. {
  6271. // Store the argument for later processing
  6272. asSDeferredParam outParam;
  6273. outParam.argNode = args[n]->exprNode;
  6274. outParam.argType = args[n]->type;
  6275. outParam.argInOutFlags = descr->inOutFlags[n];
  6276. outParam.origExpr = args[n]->origExpr;
  6277. ctx->deferredParams.PushLast(outParam);
  6278. }
  6279. }
  6280. else
  6281. {
  6282. // Release the temporary variable now
  6283. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  6284. }
  6285. // Move the argument's deferred expressions over to the final expression
  6286. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  6287. {
  6288. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  6289. args[n]->deferredParams[m].origExpr = 0;
  6290. }
  6291. args[n]->deferredParams.SetLength(0);
  6292. }
  6293. }
  6294. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  6295. {
  6296. if( isProcessingDeferredParams ) return;
  6297. isProcessingDeferredParams = true;
  6298. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  6299. {
  6300. asSDeferredParam outParam = ctx->deferredParams[n];
  6301. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  6302. {
  6303. // Just release the variable
  6304. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6305. }
  6306. else if( outParam.argInOutFlags == asTM_OUTREF )
  6307. {
  6308. asSExprContext *expr = outParam.origExpr;
  6309. outParam.origExpr = 0;
  6310. if( outParam.argType.dataType.IsObjectHandle() )
  6311. {
  6312. // Implicitly convert the value to a handle
  6313. if( expr->type.dataType.IsObjectHandle() )
  6314. expr->type.isExplicitHandle = true;
  6315. }
  6316. // Verify that the expression result in a lvalue, or a property accessor
  6317. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  6318. {
  6319. asSExprContext rctx(engine);
  6320. rctx.type = outParam.argType;
  6321. if( rctx.type.dataType.IsPrimitive() )
  6322. rctx.type.dataType.MakeReference(false);
  6323. else
  6324. {
  6325. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  6326. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  6327. if( expr->type.isExplicitHandle )
  6328. rctx.type.isExplicitHandle = true;
  6329. }
  6330. asSExprContext o(engine);
  6331. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  6332. if( !o.type.dataType.IsPrimitive() ) o.bc.Pop(AS_PTR_SIZE);
  6333. MergeExprBytecode(ctx, &o);
  6334. }
  6335. else
  6336. {
  6337. // We must still evaluate the expression
  6338. MergeExprBytecode(ctx, expr);
  6339. if( !expr->type.isConstant || expr->type.IsNullConstant() )
  6340. ctx->bc.Pop(expr->type.dataType.GetSizeOnStackDWords());
  6341. // Give a warning, except if the argument is null or 0 which indicate the argument is really to be ignored
  6342. if( !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  6343. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  6344. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6345. }
  6346. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  6347. // Delete the original expression context
  6348. asDELETE(expr,asSExprContext);
  6349. }
  6350. else // &inout
  6351. {
  6352. if( outParam.argType.isTemporary )
  6353. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6354. else if( !outParam.argType.isVariable )
  6355. {
  6356. if( outParam.argType.dataType.IsObject() &&
  6357. outParam.argType.dataType.GetBehaviour()->addref &&
  6358. outParam.argType.dataType.GetBehaviour()->release )
  6359. {
  6360. // Release the object handle that was taken to guarantee the reference
  6361. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6362. }
  6363. }
  6364. }
  6365. }
  6366. ctx->deferredParams.SetLength(0);
  6367. isProcessingDeferredParams = false;
  6368. }
  6369. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  6370. {
  6371. // The first node is a datatype node
  6372. asCString name;
  6373. asCTypeInfo tempObj;
  6374. bool onHeap = true;
  6375. asCArray<int> funcs;
  6376. // It is possible that the name is really a constructor
  6377. asCDataType dt;
  6378. dt = builder->CreateDataTypeFromNode(node->firstChild, script);
  6379. if( dt.IsPrimitive() )
  6380. {
  6381. // This is a cast to a primitive type
  6382. CompileConversion(node, ctx);
  6383. return;
  6384. }
  6385. // Do not allow constructing non-shared types in shared functions
  6386. if( outFunc->objectType && outFunc->objectType->IsShared() &&
  6387. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  6388. {
  6389. asCString msg;
  6390. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  6391. Error(msg.AddressOf(), node);
  6392. }
  6393. // Compile the arguments
  6394. asCArray<asSExprContext *> args;
  6395. asCArray<asCTypeInfo> temporaryVariables;
  6396. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6397. {
  6398. // Check for a value cast behaviour
  6399. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  6400. {
  6401. asSExprContext conv(engine);
  6402. conv.type = args[0]->type;
  6403. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  6404. if( conv.type.dataType.IsEqualExceptRef(dt) )
  6405. {
  6406. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  6407. ctx->bc.AddCode(&args[0]->bc);
  6408. ctx->type = args[0]->type;
  6409. asDELETE(args[0],asSExprContext);
  6410. return;
  6411. }
  6412. }
  6413. // Check for possible constructor/factory
  6414. name = dt.Format();
  6415. asSTypeBehaviour *beh = dt.GetBehaviour();
  6416. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6417. {
  6418. funcs = beh->constructors;
  6419. // Value types and script types are allocated through the constructor
  6420. tempObj.dataType = dt;
  6421. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  6422. tempObj.dataType.MakeReference(true);
  6423. tempObj.isTemporary = true;
  6424. tempObj.isVariable = true;
  6425. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6426. // Push the address of the object on the stack
  6427. if( onHeap )
  6428. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6429. }
  6430. else
  6431. {
  6432. funcs = beh->factories;
  6433. }
  6434. // Special case: Allow calling func(void) with a void expression.
  6435. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6436. {
  6437. // Evaluate the expression before the function call
  6438. MergeExprBytecode(ctx, args[0]);
  6439. asDELETE(args[0],asSExprContext);
  6440. args.SetLength(0);
  6441. }
  6442. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  6443. // If none has been registered, just allocate the variable and push it on the stack.
  6444. if( args.GetLength() == 0 )
  6445. {
  6446. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  6447. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  6448. {
  6449. // Call the default constructor
  6450. ctx->type = tempObj;
  6451. if( onHeap )
  6452. {
  6453. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  6454. ctx->bc.RemoveLastInstr();
  6455. }
  6456. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  6457. // Push the reference on the stack
  6458. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6459. return;
  6460. }
  6461. }
  6462. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  6463. if( funcs.GetLength() != 1 )
  6464. {
  6465. // The error was reported by MatchFunctions()
  6466. // Dummy value
  6467. ctx->type.SetDummy();
  6468. }
  6469. else
  6470. {
  6471. int r = asSUCCESS;
  6472. // Add the default values for arguments not explicitly supplied
  6473. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6474. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6475. r = CompileDefaultArgs(node, args, func);
  6476. if( r == asSUCCESS )
  6477. {
  6478. asCByteCode objBC(engine);
  6479. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6480. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6481. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6482. {
  6483. // If the object is allocated on the stack, then call the constructor as a normal function
  6484. if( onHeap )
  6485. {
  6486. int offset = 0;
  6487. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6488. for( asUINT n = 0; n < args.GetLength(); n++ )
  6489. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6490. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6491. }
  6492. else
  6493. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6494. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  6495. // Add tag that the object has been initialized
  6496. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6497. // The constructor doesn't return anything,
  6498. // so we have to manually inform the type of
  6499. // the return value
  6500. ctx->type = tempObj;
  6501. if( !onHeap )
  6502. ctx->type.dataType.MakeReference(false);
  6503. // Push the address of the object on the stack again
  6504. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6505. }
  6506. else
  6507. {
  6508. // Call the factory to create the reference type
  6509. PerformFunctionCall(funcs[0], ctx, false, &args);
  6510. }
  6511. }
  6512. }
  6513. }
  6514. else
  6515. {
  6516. // Failed to compile the argument list, set the result to the dummy type
  6517. ctx->type.SetDummy();
  6518. }
  6519. // Cleanup
  6520. for( asUINT n = 0; n < args.GetLength(); n++ )
  6521. if( args[n] )
  6522. {
  6523. asDELETE(args[n],asSExprContext);
  6524. }
  6525. }
  6526. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  6527. {
  6528. asCString name;
  6529. asCTypeInfo tempObj;
  6530. asCArray<int> funcs;
  6531. int r = -1;
  6532. asCScriptNode *nm = node->lastChild->prev;
  6533. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  6534. // First check for a local variable of a function type
  6535. // Must not allow function names, nor global variables to be returned in this instance
  6536. asSExprContext funcPtr(engine);
  6537. if( objectType == 0 )
  6538. r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  6539. if( r < 0 )
  6540. {
  6541. if( objectType )
  6542. {
  6543. // If we're compiling a constructor and the name of the function is super then
  6544. // the constructor of the base class is being called.
  6545. // super cannot be prefixed with a scope operator
  6546. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  6547. {
  6548. // If the class is not derived from anyone else, calling super should give an error
  6549. if( objectType->derivedFrom )
  6550. funcs = objectType->derivedFrom->beh.constructors;
  6551. }
  6552. else
  6553. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType, funcs, objIsConst, scope);
  6554. // It is still possible that there is a class member of a function type
  6555. if( funcs.GetLength() == 0 )
  6556. CompileVariableAccess(name, scope, &funcPtr, node, true, true, objectType);
  6557. }
  6558. else
  6559. {
  6560. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  6561. // TODO: funcdef: It is still possible that there is a global variable of a function type
  6562. }
  6563. }
  6564. else if( !funcPtr.type.dataType.GetFuncDef() )
  6565. {
  6566. // The variable is not a function
  6567. asCString msg;
  6568. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  6569. Error(msg.AddressOf(), node);
  6570. return -1;
  6571. }
  6572. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  6573. {
  6574. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  6575. }
  6576. // Compile the arguments
  6577. asCArray<asSExprContext *> args;
  6578. asCArray<asCTypeInfo> temporaryVariables;
  6579. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6580. {
  6581. // Special case: Allow calling func(void) with a void expression.
  6582. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6583. {
  6584. // Evaluate the expression before the function call
  6585. MergeExprBytecode(ctx, args[0]);
  6586. asDELETE(args[0],asSExprContext);
  6587. args.SetLength(0);
  6588. }
  6589. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  6590. if( funcs.GetLength() != 1 )
  6591. {
  6592. // The error was reported by MatchFunctions()
  6593. // Dummy value
  6594. ctx->type.SetDummy();
  6595. }
  6596. else
  6597. {
  6598. int r = asSUCCESS;
  6599. // Add the default values for arguments not explicitly supplied
  6600. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6601. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6602. r = CompileDefaultArgs(node, args, func);
  6603. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  6604. // is it enough to make sure it is in a local variable?
  6605. // For function pointer we must guarantee that the function is safe, i.e.
  6606. // by first storing the function pointer in a local variable (if it isn't already in one)
  6607. if( r == asSUCCESS )
  6608. {
  6609. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6610. {
  6611. if( objectType )
  6612. {
  6613. Dereference(ctx, true); // Dereference the object pointer to access the member
  6614. // The actual function should be called as if a global function
  6615. objectType = 0;
  6616. }
  6617. Dereference(&funcPtr, true);
  6618. ConvertToVariable(&funcPtr);
  6619. ctx->bc.AddCode(&funcPtr.bc);
  6620. if( !funcPtr.type.isTemporary )
  6621. ctx->bc.Pop(AS_PTR_SIZE);
  6622. }
  6623. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  6624. // If the function pointer was copied to a local variable for the call, then
  6625. // release it again (temporary local variable)
  6626. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6627. {
  6628. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  6629. }
  6630. }
  6631. }
  6632. }
  6633. else
  6634. {
  6635. // Failed to compile the argument list, set the dummy type and continue compilation
  6636. ctx->type.SetDummy();
  6637. }
  6638. // Cleanup
  6639. for( asUINT n = 0; n < args.GetLength(); n++ )
  6640. if( args[n] )
  6641. {
  6642. asDELETE(args[n],asSExprContext);
  6643. }
  6644. return 0;
  6645. }
  6646. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  6647. {
  6648. int op = node->tokenType;
  6649. IsVariableInitialized(&ctx->type, node);
  6650. if( op == ttHandle )
  6651. {
  6652. // Verify that the type allow its handle to be taken
  6653. if( ctx->type.isExplicitHandle ||
  6654. !ctx->type.dataType.IsObject() ||
  6655. !((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) ||
  6656. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  6657. {
  6658. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  6659. return -1;
  6660. }
  6661. // Objects that are not local variables are not references
  6662. // Objects allocated on the stack are also not marked as references
  6663. if( !ctx->type.dataType.IsReference() &&
  6664. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  6665. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  6666. {
  6667. Error(TXT_NOT_VALID_REFERENCE, node);
  6668. return -1;
  6669. }
  6670. // If this is really an object then the handle created is a const handle
  6671. bool makeConst = !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE);
  6672. // Mark the type as an object handle
  6673. ctx->type.dataType.MakeHandle(true);
  6674. ctx->type.isExplicitHandle = true;
  6675. if( makeConst )
  6676. ctx->type.dataType.MakeReadOnly(true);
  6677. }
  6678. else if( (op == ttMinus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6679. {
  6680. // Look for the appropriate method
  6681. const char *opName = 0;
  6682. switch( op )
  6683. {
  6684. case ttMinus: opName = "opNeg"; break;
  6685. case ttBitNot: opName = "opCom"; break;
  6686. case ttInc: opName = "opPreInc"; break;
  6687. case ttDec: opName = "opPreDec"; break;
  6688. }
  6689. if( opName )
  6690. {
  6691. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6692. ProcessPropertyGetAccessor(ctx, node);
  6693. // Is it a const value?
  6694. bool isConst = false;
  6695. if( ctx->type.dataType.IsObjectHandle() )
  6696. isConst = ctx->type.dataType.IsHandleToConst();
  6697. else
  6698. isConst = ctx->type.dataType.IsReadOnly();
  6699. // 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
  6700. // Find the correct method
  6701. asCArray<int> funcs;
  6702. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6703. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6704. {
  6705. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6706. if( func->name == opName &&
  6707. func->parameterTypes.GetLength() == 0 &&
  6708. (!isConst || func->isReadOnly) )
  6709. {
  6710. funcs.PushLast(func->id);
  6711. }
  6712. }
  6713. // Did we find the method?
  6714. if( funcs.GetLength() == 1 )
  6715. {
  6716. asCTypeInfo objType = ctx->type;
  6717. asCArray<asSExprContext *> args;
  6718. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6719. ReleaseTemporaryVariable(objType, &ctx->bc);
  6720. return 0;
  6721. }
  6722. else if( funcs.GetLength() == 0 )
  6723. {
  6724. asCString str;
  6725. str = asCString(opName) + "()";
  6726. if( isConst )
  6727. str += " const";
  6728. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6729. Error(str.AddressOf(), node);
  6730. ctx->type.SetDummy();
  6731. return -1;
  6732. }
  6733. else if( funcs.GetLength() > 1 )
  6734. {
  6735. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6736. PrintMatchingFuncs(funcs, node);
  6737. ctx->type.SetDummy();
  6738. return -1;
  6739. }
  6740. }
  6741. }
  6742. else if( op == ttPlus || op == ttMinus )
  6743. {
  6744. ProcessPropertyGetAccessor(ctx, node);
  6745. asCDataType to = ctx->type.dataType;
  6746. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  6747. if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
  6748. {
  6749. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6750. to = asCDataType::CreatePrimitive(ttInt8, false);
  6751. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6752. to = asCDataType::CreatePrimitive(ttInt16, false);
  6753. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6754. to = asCDataType::CreatePrimitive(ttInt, false);
  6755. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6756. to = asCDataType::CreatePrimitive(ttInt64, false);
  6757. else
  6758. {
  6759. Error(TXT_INVALID_TYPE, node);
  6760. return -1;
  6761. }
  6762. }
  6763. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6764. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6765. if( !ctx->type.isConstant )
  6766. {
  6767. ConvertToTempVariable(ctx);
  6768. asASSERT(!ctx->type.isLValue);
  6769. if( op == ttMinus )
  6770. {
  6771. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6772. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  6773. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6774. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  6775. else if( ctx->type.dataType.IsFloatType() )
  6776. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  6777. else if( ctx->type.dataType.IsDoubleType() )
  6778. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  6779. else
  6780. {
  6781. Error(TXT_ILLEGAL_OPERATION, node);
  6782. return -1;
  6783. }
  6784. return 0;
  6785. }
  6786. }
  6787. else
  6788. {
  6789. if( op == ttMinus )
  6790. {
  6791. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6792. ctx->type.intValue = -ctx->type.intValue;
  6793. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6794. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  6795. else if( ctx->type.dataType.IsFloatType() )
  6796. ctx->type.floatValue = -ctx->type.floatValue;
  6797. else if( ctx->type.dataType.IsDoubleType() )
  6798. ctx->type.doubleValue = -ctx->type.doubleValue;
  6799. else
  6800. {
  6801. Error(TXT_ILLEGAL_OPERATION, node);
  6802. return -1;
  6803. }
  6804. return 0;
  6805. }
  6806. }
  6807. if( op == ttPlus )
  6808. {
  6809. if( !ctx->type.dataType.IsIntegerType() &&
  6810. !ctx->type.dataType.IsFloatType() &&
  6811. !ctx->type.dataType.IsDoubleType() )
  6812. {
  6813. Error(TXT_ILLEGAL_OPERATION, node);
  6814. return -1;
  6815. }
  6816. }
  6817. }
  6818. else if( op == ttNot )
  6819. {
  6820. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6821. {
  6822. if( ctx->type.isConstant )
  6823. {
  6824. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  6825. return 0;
  6826. }
  6827. ProcessPropertyGetAccessor(ctx, node);
  6828. ConvertToTempVariable(ctx);
  6829. asASSERT(!ctx->type.isLValue);
  6830. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  6831. }
  6832. else
  6833. {
  6834. Error(TXT_ILLEGAL_OPERATION, node);
  6835. return -1;
  6836. }
  6837. }
  6838. else if( op == ttBitNot )
  6839. {
  6840. ProcessPropertyGetAccessor(ctx, node);
  6841. asCDataType to = ctx->type.dataType;
  6842. if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
  6843. {
  6844. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6845. to = asCDataType::CreatePrimitive(ttUInt8, false);
  6846. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6847. to = asCDataType::CreatePrimitive(ttUInt16, false);
  6848. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6849. to = asCDataType::CreatePrimitive(ttUInt, false);
  6850. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6851. to = asCDataType::CreatePrimitive(ttUInt64, false);
  6852. else
  6853. {
  6854. Error(TXT_INVALID_TYPE, node);
  6855. return -1;
  6856. }
  6857. }
  6858. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6859. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6860. if( ctx->type.dataType.IsUnsignedType() )
  6861. {
  6862. if( ctx->type.isConstant )
  6863. {
  6864. ctx->type.qwordValue = ~ctx->type.qwordValue;
  6865. return 0;
  6866. }
  6867. ConvertToTempVariable(ctx);
  6868. asASSERT(!ctx->type.isLValue);
  6869. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6870. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  6871. else
  6872. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  6873. }
  6874. else
  6875. {
  6876. Error(TXT_ILLEGAL_OPERATION, node);
  6877. return -1;
  6878. }
  6879. }
  6880. else if( op == ttInc || op == ttDec )
  6881. {
  6882. // Need a reference to the primitive that will be updated
  6883. // The result of this expression is the same reference as before
  6884. // Make sure the reference isn't a temporary variable
  6885. if( ctx->type.isTemporary )
  6886. {
  6887. Error(TXT_REF_IS_TEMP, node);
  6888. return -1;
  6889. }
  6890. if( ctx->type.dataType.IsReadOnly() )
  6891. {
  6892. Error(TXT_REF_IS_READ_ONLY, node);
  6893. return -1;
  6894. }
  6895. if( ctx->property_get || ctx->property_set )
  6896. {
  6897. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6898. return -1;
  6899. }
  6900. if( !ctx->type.isLValue )
  6901. {
  6902. Error(TXT_NOT_LVALUE, node);
  6903. return -1;
  6904. }
  6905. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6906. ConvertToReference(ctx);
  6907. else if( !ctx->type.dataType.IsReference() )
  6908. {
  6909. Error(TXT_NOT_VALID_REFERENCE, node);
  6910. return -1;
  6911. }
  6912. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6913. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6914. {
  6915. if( op == ttInc )
  6916. ctx->bc.Instr(asBC_INCi64);
  6917. else
  6918. ctx->bc.Instr(asBC_DECi64);
  6919. }
  6920. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  6921. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  6922. {
  6923. if( op == ttInc )
  6924. ctx->bc.Instr(asBC_INCi);
  6925. else
  6926. ctx->bc.Instr(asBC_DECi);
  6927. }
  6928. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6929. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6930. {
  6931. if( op == ttInc )
  6932. ctx->bc.Instr(asBC_INCi16);
  6933. else
  6934. ctx->bc.Instr(asBC_DECi16);
  6935. }
  6936. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6937. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6938. {
  6939. if( op == ttInc )
  6940. ctx->bc.Instr(asBC_INCi8);
  6941. else
  6942. ctx->bc.Instr(asBC_DECi8);
  6943. }
  6944. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  6945. {
  6946. if( op == ttInc )
  6947. ctx->bc.Instr(asBC_INCf);
  6948. else
  6949. ctx->bc.Instr(asBC_DECf);
  6950. }
  6951. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  6952. {
  6953. if( op == ttInc )
  6954. ctx->bc.Instr(asBC_INCd);
  6955. else
  6956. ctx->bc.Instr(asBC_DECd);
  6957. }
  6958. else
  6959. {
  6960. Error(TXT_ILLEGAL_OPERATION, node);
  6961. return -1;
  6962. }
  6963. }
  6964. else
  6965. {
  6966. // Unknown operator
  6967. asASSERT(false);
  6968. return -1;
  6969. }
  6970. return 0;
  6971. }
  6972. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  6973. {
  6974. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6975. {
  6976. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  6977. ctx->type.dataType.MakeReference(true);
  6978. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  6979. }
  6980. }
  6981. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, bool isThisAccess)
  6982. {
  6983. return FindPropertyAccessor(name, ctx, 0, node, isThisAccess);
  6984. }
  6985. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, bool isThisAccess)
  6986. {
  6987. if( engine->ep.propertyAccessorMode == 0 )
  6988. {
  6989. // Property accessors have been disabled by the application
  6990. return 0;
  6991. }
  6992. int getId = 0, setId = 0;
  6993. asCString getName = "get_" + name;
  6994. asCString setName = "set_" + name;
  6995. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  6996. if( ctx->type.dataType.IsObject() )
  6997. {
  6998. // Check if the object has any methods with the corresponding accessor name(s)
  6999. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7000. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7001. {
  7002. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7003. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7004. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7005. {
  7006. if( getId == 0 )
  7007. getId = ot->methods[n];
  7008. else
  7009. {
  7010. if( multipleGetFuncs.GetLength() == 0 )
  7011. multipleGetFuncs.PushLast(getId);
  7012. multipleGetFuncs.PushLast(ot->methods[n]);
  7013. }
  7014. }
  7015. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7016. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7017. {
  7018. if( setId == 0 )
  7019. setId = ot->methods[n];
  7020. else
  7021. {
  7022. if( multipleSetFuncs.GetLength() == 0 )
  7023. multipleSetFuncs.PushLast(setId);
  7024. multipleSetFuncs.PushLast(ot->methods[n]);
  7025. }
  7026. }
  7027. }
  7028. }
  7029. else
  7030. {
  7031. // Look for appropriate global functions.
  7032. asCArray<int> funcs;
  7033. asUINT n;
  7034. builder->GetFunctionDescriptions(getName.AddressOf(), funcs);
  7035. for( n = 0; n < funcs.GetLength(); n++ )
  7036. {
  7037. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7038. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7039. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7040. {
  7041. if( getId == 0 )
  7042. getId = funcs[n];
  7043. else
  7044. {
  7045. if( multipleGetFuncs.GetLength() == 0 )
  7046. multipleGetFuncs.PushLast(getId);
  7047. multipleGetFuncs.PushLast(funcs[n]);
  7048. }
  7049. }
  7050. }
  7051. funcs.SetLength(0);
  7052. builder->GetFunctionDescriptions(setName.AddressOf(), funcs);
  7053. for( n = 0; n < funcs.GetLength(); n++ )
  7054. {
  7055. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7056. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7057. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7058. {
  7059. if( setId == 0 )
  7060. setId = funcs[n];
  7061. else
  7062. {
  7063. if( multipleSetFuncs.GetLength() == 0 )
  7064. multipleSetFuncs.PushLast(getId);
  7065. multipleSetFuncs.PushLast(funcs[n]);
  7066. }
  7067. }
  7068. }
  7069. }
  7070. // Check for multiple matches
  7071. if( multipleGetFuncs.GetLength() > 0 )
  7072. {
  7073. asCString str;
  7074. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  7075. Error(str.AddressOf(), node);
  7076. PrintMatchingFuncs(multipleGetFuncs, node);
  7077. return -1;
  7078. }
  7079. if( multipleSetFuncs.GetLength() > 0 )
  7080. {
  7081. asCString str;
  7082. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  7083. Error(str.AddressOf(), node);
  7084. PrintMatchingFuncs(multipleSetFuncs, node);
  7085. return -1;
  7086. }
  7087. // Check for type compatibility between get and set accessor
  7088. if( getId && setId )
  7089. {
  7090. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  7091. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  7092. // It is permitted for a getter to return a handle and the setter to take a reference
  7093. int idx = (arg?1:0);
  7094. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  7095. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  7096. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  7097. {
  7098. asCString str;
  7099. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  7100. Error(str.AddressOf(), node);
  7101. asCArray<int> funcs;
  7102. funcs.PushLast(getId);
  7103. funcs.PushLast(setId);
  7104. PrintMatchingFuncs(funcs, node);
  7105. return -1;
  7106. }
  7107. }
  7108. // Check if we are within one of the accessors
  7109. int realGetId = getId;
  7110. int realSetId = setId;
  7111. if( outFunc->objectType && isThisAccess )
  7112. {
  7113. // The property accessors would be virtual functions, so we need to find the real implementation
  7114. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  7115. if( getFunc &&
  7116. getFunc->funcType == asFUNC_VIRTUAL &&
  7117. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  7118. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  7119. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  7120. if( setFunc &&
  7121. setFunc->funcType == asFUNC_VIRTUAL &&
  7122. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  7123. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  7124. }
  7125. // Avoid recursive call, by not treating this as a property accessor call.
  7126. // This will also allow having the real property with the same name as the accessors.
  7127. if( (isThisAccess || outFunc->objectType == 0) &&
  7128. ((realGetId && realGetId == outFunc->id) ||
  7129. (realSetId && realSetId == outFunc->id)) )
  7130. {
  7131. getId = 0;
  7132. setId = 0;
  7133. }
  7134. // Check if the application has disabled script written property accessors
  7135. if( engine->ep.propertyAccessorMode == 1 )
  7136. {
  7137. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  7138. getId = 0;
  7139. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  7140. setId = 0;
  7141. }
  7142. if( getId || setId )
  7143. {
  7144. // Property accessors were found, but we don't know which is to be used yet, so
  7145. // we just prepare the bytecode for the method call, and then store the function ids
  7146. // so that the right one can be used when we get there.
  7147. ctx->property_get = getId;
  7148. ctx->property_set = setId;
  7149. if( ctx->type.dataType.IsObject() )
  7150. {
  7151. // If the object is read-only then we need to remember that
  7152. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  7153. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  7154. ctx->property_const = true;
  7155. else
  7156. ctx->property_const = false;
  7157. // If the object is a handle then we need to remember that
  7158. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  7159. ctx->property_ref = ctx->type.dataType.IsReference();
  7160. }
  7161. // The setter's parameter type is used as the property type,
  7162. // unless only the getter is available
  7163. asCDataType dt;
  7164. if( setId )
  7165. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  7166. else
  7167. dt = builder->GetFunctionDescription(getId)->returnType;
  7168. // Just change the type, the context must still maintain information
  7169. // about previous variable offset and the indicator of temporary variable.
  7170. int offset = ctx->type.stackOffset;
  7171. bool isTemp = ctx->type.isTemporary;
  7172. ctx->type.Set(dt);
  7173. ctx->type.stackOffset = (short)offset;
  7174. ctx->type.isTemporary = isTemp;
  7175. ctx->exprNode = node;
  7176. // Store the argument for later use
  7177. if( arg )
  7178. {
  7179. ctx->property_arg = asNEW(asSExprContext)(engine);
  7180. MergeExprBytecodeAndType(ctx->property_arg, arg);
  7181. }
  7182. return 1;
  7183. }
  7184. // No accessor was found
  7185. return 0;
  7186. }
  7187. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  7188. {
  7189. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  7190. if( !ctx->property_set )
  7191. {
  7192. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  7193. return -1;
  7194. }
  7195. asCTypeInfo objType = ctx->type;
  7196. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  7197. // Make sure the arg match the property
  7198. asCArray<int> funcs;
  7199. funcs.PushLast(ctx->property_set);
  7200. asCArray<asSExprContext *> args;
  7201. if( ctx->property_arg )
  7202. args.PushLast(ctx->property_arg);
  7203. args.PushLast(arg);
  7204. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7205. if( funcs.GetLength() == 0 )
  7206. {
  7207. // MatchFunctions already reported the error
  7208. if( ctx->property_arg )
  7209. {
  7210. asDELETE(ctx->property_arg, asSExprContext);
  7211. ctx->property_arg = 0;
  7212. }
  7213. return -1;
  7214. }
  7215. if( func->objectType )
  7216. {
  7217. // Setup the context with the original type so the method call gets built correctly
  7218. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7219. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7220. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7221. // Don't allow the call if the object is read-only and the property accessor is not const
  7222. if( ctx->property_const && !func->isReadOnly )
  7223. {
  7224. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7225. asCArray<int> funcs;
  7226. funcs.PushLast(ctx->property_set);
  7227. PrintMatchingFuncs(funcs, node);
  7228. }
  7229. }
  7230. // Call the accessor
  7231. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  7232. if( func->objectType )
  7233. {
  7234. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  7235. if( !objType.isTemporary ||
  7236. !ctx->type.dataType.IsReference() ||
  7237. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7238. {
  7239. // As the method didn't return a reference to a member
  7240. // we can safely release the original object now
  7241. ReleaseTemporaryVariable(objType, &ctx->bc);
  7242. }
  7243. }
  7244. ctx->property_get = 0;
  7245. ctx->property_set = 0;
  7246. if( ctx->property_arg )
  7247. {
  7248. asDELETE(ctx->property_arg, asSExprContext);
  7249. ctx->property_arg = 0;
  7250. }
  7251. return 0;
  7252. }
  7253. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  7254. {
  7255. // If no property accessor has been prepared then don't do anything
  7256. if( !ctx->property_get && !ctx->property_set )
  7257. return;
  7258. if( !ctx->property_get )
  7259. {
  7260. // Raise error on missing accessor
  7261. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  7262. ctx->type.SetDummy();
  7263. return;
  7264. }
  7265. asCTypeInfo objType = ctx->type;
  7266. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  7267. // Make sure the arg match the property
  7268. asCArray<int> funcs;
  7269. funcs.PushLast(ctx->property_get);
  7270. asCArray<asSExprContext *> args;
  7271. if( ctx->property_arg )
  7272. args.PushLast(ctx->property_arg);
  7273. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7274. if( funcs.GetLength() == 0 )
  7275. {
  7276. // MatchFunctions already reported the error
  7277. if( ctx->property_arg )
  7278. {
  7279. asDELETE(ctx->property_arg, asSExprContext);
  7280. ctx->property_arg = 0;
  7281. }
  7282. ctx->type.SetDummy();
  7283. return;
  7284. }
  7285. if( func->objectType )
  7286. {
  7287. // Setup the context with the original type so the method call gets built correctly
  7288. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7289. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7290. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7291. // Don't allow the call if the object is read-only and the property accessor is not const
  7292. if( ctx->property_const && !func->isReadOnly )
  7293. {
  7294. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7295. asCArray<int> funcs;
  7296. funcs.PushLast(ctx->property_get);
  7297. PrintMatchingFuncs(funcs, node);
  7298. }
  7299. }
  7300. // Call the accessor
  7301. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  7302. if( func->objectType )
  7303. {
  7304. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  7305. if( !objType.isTemporary ||
  7306. !ctx->type.dataType.IsReference() ||
  7307. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7308. {
  7309. // As the method didn't return a reference to a member
  7310. // we can safely release the original object now
  7311. ReleaseTemporaryVariable(objType, &ctx->bc);
  7312. }
  7313. }
  7314. ctx->property_get = 0;
  7315. ctx->property_set = 0;
  7316. if( ctx->property_arg )
  7317. {
  7318. asDELETE(ctx->property_arg, asSExprContext);
  7319. ctx->property_arg = 0;
  7320. }
  7321. }
  7322. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  7323. {
  7324. int op = node->tokenType;
  7325. // Check if the variable is initialized (if it indeed is a variable)
  7326. IsVariableInitialized(&ctx->type, node);
  7327. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7328. {
  7329. const char *opName = 0;
  7330. switch( op )
  7331. {
  7332. case ttInc: opName = "opPostInc"; break;
  7333. case ttDec: opName = "opPostDec"; break;
  7334. }
  7335. if( opName )
  7336. {
  7337. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7338. ProcessPropertyGetAccessor(ctx, node);
  7339. // Is it a const value?
  7340. bool isConst = false;
  7341. if( ctx->type.dataType.IsObjectHandle() )
  7342. isConst = ctx->type.dataType.IsHandleToConst();
  7343. else
  7344. isConst = ctx->type.dataType.IsReadOnly();
  7345. // 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
  7346. // Find the correct method
  7347. asCArray<int> funcs;
  7348. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7349. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7350. {
  7351. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7352. if( func->name == opName &&
  7353. func->parameterTypes.GetLength() == 0 &&
  7354. (!isConst || func->isReadOnly) )
  7355. {
  7356. funcs.PushLast(func->id);
  7357. }
  7358. }
  7359. // Did we find the method?
  7360. if( funcs.GetLength() == 1 )
  7361. {
  7362. asCTypeInfo objType = ctx->type;
  7363. asCArray<asSExprContext *> args;
  7364. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7365. ReleaseTemporaryVariable(objType, &ctx->bc);
  7366. return 0;
  7367. }
  7368. else if( funcs.GetLength() == 0 )
  7369. {
  7370. asCString str;
  7371. str = asCString(opName) + "()";
  7372. if( isConst )
  7373. str += " const";
  7374. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7375. Error(str.AddressOf(), node);
  7376. ctx->type.SetDummy();
  7377. return -1;
  7378. }
  7379. else if( funcs.GetLength() > 1 )
  7380. {
  7381. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7382. PrintMatchingFuncs(funcs, node);
  7383. ctx->type.SetDummy();
  7384. return -1;
  7385. }
  7386. }
  7387. }
  7388. else if( op == ttInc || op == ttDec )
  7389. {
  7390. // Make sure the reference isn't a temporary variable
  7391. if( ctx->type.isTemporary )
  7392. {
  7393. Error(TXT_REF_IS_TEMP, node);
  7394. return -1;
  7395. }
  7396. if( ctx->type.dataType.IsReadOnly() )
  7397. {
  7398. Error(TXT_REF_IS_READ_ONLY, node);
  7399. return -1;
  7400. }
  7401. if( ctx->property_get || ctx->property_set )
  7402. {
  7403. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7404. return -1;
  7405. }
  7406. if( !ctx->type.isLValue )
  7407. {
  7408. Error(TXT_NOT_LVALUE, node);
  7409. return -1;
  7410. }
  7411. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7412. ConvertToReference(ctx);
  7413. else if( !ctx->type.dataType.IsReference() )
  7414. {
  7415. Error(TXT_NOT_VALID_REFERENCE, node);
  7416. return -1;
  7417. }
  7418. // Copy the value to a temp before changing it
  7419. ConvertToTempVariable(ctx);
  7420. asASSERT(!ctx->type.isLValue);
  7421. // Increment the value pointed to by the reference still in the register
  7422. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  7423. if( ctx->type.dataType.IsDoubleType() )
  7424. {
  7425. iInc = asBC_INCd;
  7426. iDec = asBC_DECd;
  7427. }
  7428. else if( ctx->type.dataType.IsFloatType() )
  7429. {
  7430. iInc = asBC_INCf;
  7431. iDec = asBC_DECf;
  7432. }
  7433. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  7434. {
  7435. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7436. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7437. {
  7438. iInc = asBC_INCi16;
  7439. iDec = asBC_DECi16;
  7440. }
  7441. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7442. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7443. {
  7444. iInc = asBC_INCi8;
  7445. iDec = asBC_DECi8;
  7446. }
  7447. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7448. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7449. {
  7450. iInc = asBC_INCi64;
  7451. iDec = asBC_DECi64;
  7452. }
  7453. }
  7454. else
  7455. {
  7456. Error(TXT_ILLEGAL_OPERATION, node);
  7457. return -1;
  7458. }
  7459. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  7460. }
  7461. else if( op == ttDot )
  7462. {
  7463. if( node->firstChild->nodeType == snIdentifier )
  7464. {
  7465. ProcessPropertyGetAccessor(ctx, node);
  7466. // Get the property name
  7467. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  7468. // We need to look for get/set property accessors.
  7469. // If found, the context stores information on the get/set accessors
  7470. // until it is known which is to be used.
  7471. int r = 0;
  7472. if( node->next && node->next->tokenType == ttOpenBracket )
  7473. {
  7474. // The property accessor should take an index arg
  7475. asSExprContext dummyArg(engine);
  7476. r = FindPropertyAccessor(name, ctx, &dummyArg, node);
  7477. }
  7478. if( r == 0 )
  7479. r = FindPropertyAccessor(name, ctx, node);
  7480. if( r != 0 )
  7481. return r;
  7482. if( !ctx->type.dataType.IsPrimitive() )
  7483. Dereference(ctx, true);
  7484. if( ctx->type.dataType.IsObjectHandle() )
  7485. {
  7486. // Convert the handle to a normal object
  7487. asCDataType dt = ctx->type.dataType;
  7488. dt.MakeHandle(false);
  7489. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  7490. // The handle may not have been an lvalue, but the dereferenced object is
  7491. ctx->type.isLValue = true;
  7492. }
  7493. // Find the property offset and type
  7494. if( ctx->type.dataType.IsObject() )
  7495. {
  7496. bool isConst = ctx->type.dataType.IsReadOnly();
  7497. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  7498. if( prop )
  7499. {
  7500. // Is the property access allowed?
  7501. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  7502. {
  7503. asCString msg;
  7504. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  7505. Error(msg.AddressOf(), node);
  7506. }
  7507. // Put the offset on the stack
  7508. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  7509. if( prop->type.IsReference() )
  7510. ctx->bc.Instr(asBC_RDSPTR);
  7511. // Reference to primitive must be stored in the temp register
  7512. if( prop->type.IsPrimitive() )
  7513. {
  7514. ctx->bc.Instr(asBC_PopRPtr);
  7515. }
  7516. // Set the new type (keeping info about temp variable)
  7517. ctx->type.dataType = prop->type;
  7518. ctx->type.dataType.MakeReference(true);
  7519. ctx->type.isVariable = false;
  7520. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7521. {
  7522. // Objects that are members are not references
  7523. ctx->type.dataType.MakeReference(false);
  7524. }
  7525. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  7526. }
  7527. else
  7528. {
  7529. asCString str;
  7530. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7531. Error(str.AddressOf(), node);
  7532. return -1;
  7533. }
  7534. }
  7535. else
  7536. {
  7537. asCString str;
  7538. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7539. Error(str.AddressOf(), node);
  7540. return -1;
  7541. }
  7542. }
  7543. else
  7544. {
  7545. // Make sure it is an object we are accessing
  7546. if( !ctx->type.dataType.IsObject() )
  7547. {
  7548. asCString str;
  7549. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  7550. Error(str.AddressOf(), node);
  7551. return -1;
  7552. }
  7553. // Process the get property accessor
  7554. ProcessPropertyGetAccessor(ctx, node);
  7555. bool isConst = false;
  7556. if( ctx->type.dataType.IsObjectHandle() )
  7557. isConst = ctx->type.dataType.IsHandleToConst();
  7558. else
  7559. isConst = ctx->type.dataType.IsReadOnly();
  7560. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  7561. asCTypeInfo objType = ctx->type;
  7562. // Compile function call
  7563. int r = CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  7564. if( r < 0 ) return r;
  7565. // If the method returned a reference, then we can't release the original
  7566. // object yet, because the reference may be to a member of it
  7567. if( !objType.isTemporary ||
  7568. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  7569. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7570. {
  7571. // As the method didn't return a reference to a member
  7572. // we can safely release the original object now
  7573. ReleaseTemporaryVariable(objType, &ctx->bc);
  7574. }
  7575. }
  7576. }
  7577. else if( op == ttOpenBracket )
  7578. {
  7579. // If the property access takes an index arg, then we should use that instead of processing it now
  7580. asCString propertyName;
  7581. if( (ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  7582. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2) )
  7583. {
  7584. // Determine the name of the property accessor
  7585. asCScriptFunction *func = 0;
  7586. if( ctx->property_get )
  7587. func = builder->GetFunctionDescription(ctx->property_get);
  7588. else
  7589. func = builder->GetFunctionDescription(ctx->property_set);
  7590. propertyName = func->GetName();
  7591. propertyName = propertyName.SubString(4);
  7592. // Set the original type of the expression so we can re-evaluate the property accessor
  7593. if( func->objectType )
  7594. {
  7595. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7596. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7597. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7598. }
  7599. ctx->property_get = ctx->property_set = 0;
  7600. if( ctx->property_arg )
  7601. {
  7602. asDELETE(ctx->property_arg, asSExprContext);
  7603. ctx->property_arg = 0;
  7604. }
  7605. }
  7606. else
  7607. {
  7608. if( !ctx->type.dataType.IsObject() )
  7609. {
  7610. asCString str;
  7611. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7612. Error(str.AddressOf(), node);
  7613. return -1;
  7614. }
  7615. ProcessPropertyGetAccessor(ctx, node);
  7616. }
  7617. Dereference(ctx, true);
  7618. // Compile the expression
  7619. asSExprContext expr(engine);
  7620. CompileAssignment(node->firstChild, &expr);
  7621. // Check for the existence of the opIndex method
  7622. asSExprContext lctx(engine);
  7623. MergeExprBytecodeAndType(&lctx, ctx);
  7624. int r = 0;
  7625. if( propertyName == "" )
  7626. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  7627. if( r == 0 )
  7628. {
  7629. // Check for accessors methods for the opIndex
  7630. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node);
  7631. if( r == 0 )
  7632. {
  7633. asCString str;
  7634. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7635. Error(str.AddressOf(), node);
  7636. return -1;
  7637. }
  7638. else if( r < 0 )
  7639. return -1;
  7640. MergeExprBytecodeAndType(ctx, &lctx);
  7641. }
  7642. }
  7643. return 0;
  7644. }
  7645. int asCCompiler::GetPrecedence(asCScriptNode *op)
  7646. {
  7647. // x * y, x / y, x % y
  7648. // x + y, x - y
  7649. // x <= y, x < y, x >= y, x > y
  7650. // x = =y, x != y, x xor y, x is y, x !is y
  7651. // x and y
  7652. // x or y
  7653. // The following are not used in this function,
  7654. // but should have lower precedence than the above
  7655. // x ? y : z
  7656. // x = y
  7657. // The expression term have the highest precedence
  7658. if( op->nodeType == snExprTerm )
  7659. return 1;
  7660. // Evaluate operators by token
  7661. int tokenType = op->tokenType;
  7662. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  7663. return 0;
  7664. if( tokenType == ttPlus || tokenType == ttMinus )
  7665. return -1;
  7666. if( tokenType == ttBitShiftLeft ||
  7667. tokenType == ttBitShiftRight ||
  7668. tokenType == ttBitShiftRightArith )
  7669. return -2;
  7670. if( tokenType == ttAmp )
  7671. return -3;
  7672. if( tokenType == ttBitXor )
  7673. return -4;
  7674. if( tokenType == ttBitOr )
  7675. return -5;
  7676. if( tokenType == ttLessThanOrEqual ||
  7677. tokenType == ttLessThan ||
  7678. tokenType == ttGreaterThanOrEqual ||
  7679. tokenType == ttGreaterThan )
  7680. return -6;
  7681. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  7682. return -7;
  7683. if( tokenType == ttAnd )
  7684. return -8;
  7685. if( tokenType == ttOr )
  7686. return -9;
  7687. // Unknown operator
  7688. asASSERT(false);
  7689. return 0;
  7690. }
  7691. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<int> &matches, const asCTypeInfo *argType, int paramNum, bool allowObjectConstruct)
  7692. {
  7693. asUINT bestCost = asUINT(-1);
  7694. matches.SetLength(0);
  7695. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  7696. {
  7697. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  7698. // Does the function have arguments enough?
  7699. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  7700. continue;
  7701. // Can we make the match by implicit conversion?
  7702. asSExprContext ti(engine);
  7703. ti.type = *argType;
  7704. if( argType->dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  7705. asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  7706. // If the function parameter is an inout-reference then it must not be possible to call the
  7707. // function with an incorrect argument type, even though the type can normally be converted.
  7708. if( desc->parameterTypes[paramNum].IsReference() &&
  7709. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  7710. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7711. {
  7712. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  7713. desc->parameterTypes[paramNum].GetTokenType() != argType->dataType.GetTokenType() )
  7714. continue;
  7715. if( desc->parameterTypes[paramNum].IsEnumType() &&
  7716. desc->parameterTypes[paramNum].GetObjectType() != argType->dataType.GetObjectType() )
  7717. continue;
  7718. }
  7719. // How well does the argument match the function parameter?
  7720. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  7721. {
  7722. if( cost < bestCost )
  7723. {
  7724. matches.SetLength(0);
  7725. bestCost = cost;
  7726. }
  7727. if( cost == bestCost )
  7728. matches.PushLast(funcs[n]);
  7729. }
  7730. }
  7731. return bestCost;
  7732. }
  7733. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  7734. {
  7735. // Reference parameters whose value won't be used don't evaluate the expression
  7736. if( paramType->IsReference() && !(refType & asTM_INREF) )
  7737. {
  7738. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  7739. asSExprContext *orig = asNEW(asSExprContext)(engine);
  7740. MergeExprBytecodeAndType(orig, arg);
  7741. arg->origExpr = orig;
  7742. }
  7743. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  7744. // arg still holds the original expression for output parameters
  7745. ctx->bc.AddCode(&arg->bc);
  7746. }
  7747. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7748. {
  7749. ctx->exprNode = node;
  7750. // What type of operator is it?
  7751. int token = node->tokenType;
  7752. if( token == ttUnrecognizedToken )
  7753. {
  7754. // This happens when the compiler is inferring an assignment
  7755. // operation from another action, for example in preparing a value
  7756. // as a function argument
  7757. token = ttAssignment;
  7758. }
  7759. // boolean operators are not overloadable
  7760. if( token == ttAnd ||
  7761. token == ttOr ||
  7762. token == ttXor )
  7763. return false;
  7764. // Dual operators can also be implemented as class methods
  7765. if( token == ttEqual ||
  7766. token == ttNotEqual )
  7767. {
  7768. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7769. // Find the matching opEquals method
  7770. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7771. if( r == 0 )
  7772. {
  7773. // Try again by switching the order of the operands
  7774. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7775. }
  7776. if( r == 1 )
  7777. {
  7778. if( token == ttNotEqual )
  7779. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7780. // Success, don't continue
  7781. return true;
  7782. }
  7783. else if( r < 0 )
  7784. {
  7785. // Compiler error, don't continue
  7786. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7787. return true;
  7788. }
  7789. }
  7790. if( token == ttEqual ||
  7791. token == ttNotEqual ||
  7792. token == ttLessThan ||
  7793. token == ttLessThanOrEqual ||
  7794. token == ttGreaterThan ||
  7795. token == ttGreaterThanOrEqual )
  7796. {
  7797. bool swappedOrder = false;
  7798. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7799. // Find the matching opCmp method
  7800. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7801. if( r == 0 )
  7802. {
  7803. // Try again by switching the order of the operands
  7804. swappedOrder = true;
  7805. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7806. }
  7807. if( r == 1 )
  7808. {
  7809. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7810. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  7811. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  7812. if( token == ttEqual )
  7813. ctx->bc.Instr(asBC_TZ);
  7814. else if( token == ttNotEqual )
  7815. ctx->bc.Instr(asBC_TNZ);
  7816. else if( (token == ttLessThan && !swappedOrder) ||
  7817. (token == ttGreaterThan && swappedOrder) )
  7818. ctx->bc.Instr(asBC_TS);
  7819. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  7820. (token == ttGreaterThanOrEqual && swappedOrder) )
  7821. ctx->bc.Instr(asBC_TNP);
  7822. else if( (token == ttGreaterThan && !swappedOrder) ||
  7823. (token == ttLessThan && swappedOrder) )
  7824. ctx->bc.Instr(asBC_TP);
  7825. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  7826. (token == ttLessThanOrEqual && swappedOrder) )
  7827. ctx->bc.Instr(asBC_TNS);
  7828. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  7829. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  7830. // Success, don't continue
  7831. return true;
  7832. }
  7833. else if( r < 0 )
  7834. {
  7835. // Compiler error, don't continue
  7836. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7837. return true;
  7838. }
  7839. }
  7840. // The rest of the operators are not commutative, and doesn't require specific return type
  7841. const char *op = 0, *op_r = 0;
  7842. switch( token )
  7843. {
  7844. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  7845. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  7846. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  7847. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  7848. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  7849. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  7850. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  7851. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  7852. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  7853. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  7854. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  7855. }
  7856. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  7857. if( op && op_r )
  7858. {
  7859. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7860. // Find the matching operator method
  7861. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7862. if( r == 0 )
  7863. {
  7864. // Try again by switching the order of the operands, and using the reversed operator
  7865. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  7866. }
  7867. if( r == 1 )
  7868. {
  7869. // Success, don't continue
  7870. return true;
  7871. }
  7872. else if( r < 0 )
  7873. {
  7874. // Compiler error, don't continue
  7875. ctx->type.SetDummy();
  7876. return true;
  7877. }
  7878. }
  7879. // Assignment operators
  7880. op = 0;
  7881. switch( token )
  7882. {
  7883. case ttAssignment: op = "opAssign"; break;
  7884. case ttAddAssign: op = "opAddAssign"; break;
  7885. case ttSubAssign: op = "opSubAssign"; break;
  7886. case ttMulAssign: op = "opMulAssign"; break;
  7887. case ttDivAssign: op = "opDivAssign"; break;
  7888. case ttModAssign: op = "opModAssign"; break;
  7889. case ttOrAssign: op = "opOrAssign"; break;
  7890. case ttAndAssign: op = "opAndAssign"; break;
  7891. case ttXorAssign: op = "opXorAssign"; break;
  7892. case ttShiftLeftAssign: op = "opShlAssign"; break;
  7893. case ttShiftRightLAssign: op = "opShrAssign"; break;
  7894. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  7895. }
  7896. if( op )
  7897. {
  7898. // TODO: Shouldn't accept const lvalue with the assignment operators
  7899. // Find the matching operator method
  7900. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7901. if( r == 1 )
  7902. {
  7903. // Success, don't continue
  7904. return true;
  7905. }
  7906. else if( r < 0 )
  7907. {
  7908. // Compiler error, don't continue
  7909. ctx->type.SetDummy();
  7910. return true;
  7911. }
  7912. }
  7913. // No suitable operator was found
  7914. return false;
  7915. }
  7916. // Returns negative on compile error
  7917. // zero on no matching operator
  7918. // one on matching operator
  7919. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  7920. {
  7921. // Find the matching method
  7922. if( lctx->type.dataType.IsObject() &&
  7923. (!lctx->type.isExplicitHandle ||
  7924. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  7925. {
  7926. // Is the left value a const?
  7927. bool isConst = false;
  7928. if( lctx->type.dataType.IsObjectHandle() )
  7929. isConst = lctx->type.dataType.IsHandleToConst();
  7930. else
  7931. isConst = lctx->type.dataType.IsReadOnly();
  7932. asCArray<int> funcs;
  7933. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  7934. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7935. {
  7936. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7937. if( func->name == methodName &&
  7938. (!specificReturn || func->returnType == returnType) &&
  7939. func->parameterTypes.GetLength() == 1 &&
  7940. (!isConst || func->isReadOnly) )
  7941. {
  7942. // Make sure the method is accessible by the module
  7943. if( builder->module->accessMask & func->accessMask )
  7944. {
  7945. #ifdef AS_DEPRECATED
  7946. // deprecated since 2011-10-04
  7947. asCConfigGroup *group = engine->FindConfigGroupForFunction(func->id);
  7948. if( !group || group->HasModuleAccess(builder->module->name.AddressOf()) )
  7949. #endif
  7950. funcs.PushLast(func->id);
  7951. }
  7952. }
  7953. }
  7954. // Which is the best matching function?
  7955. asCArray<int> ops;
  7956. MatchArgument(funcs, ops, &rctx->type, 0);
  7957. // If the object is not const, then we need to prioritize non-const methods
  7958. if( !isConst )
  7959. FilterConst(ops);
  7960. // Did we find an operator?
  7961. if( ops.GetLength() == 1 )
  7962. {
  7963. // Process the lctx expression as get accessor
  7964. ProcessPropertyGetAccessor(lctx, node);
  7965. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  7966. asCTypeInfo objType = lctx->type;
  7967. asCArray<asSExprContext *> args;
  7968. args.PushLast(rctx);
  7969. MergeExprBytecode(ctx, lctx);
  7970. ctx->type = lctx->type;
  7971. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  7972. // If the method returned a reference, then we can't release the original
  7973. // object yet, because the reference may be to a member of it
  7974. if( !objType.isTemporary ||
  7975. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  7976. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  7977. {
  7978. // As the index operator didn't return a reference to a
  7979. // member we can release the original object now
  7980. ReleaseTemporaryVariable(objType, &ctx->bc);
  7981. }
  7982. // Found matching operator
  7983. return 1;
  7984. }
  7985. else if( ops.GetLength() > 1 )
  7986. {
  7987. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7988. PrintMatchingFuncs(ops, node);
  7989. ctx->type.SetDummy();
  7990. // Compiler error
  7991. return -1;
  7992. }
  7993. }
  7994. // No matching operator
  7995. return 0;
  7996. }
  7997. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  7998. {
  7999. if( objectType )
  8000. {
  8001. Dereference(ctx, true);
  8002. // This following warning was removed as there may be valid reasons
  8003. // for calling non-const methods on temporary objects, and we shouldn't
  8004. // warn when there is no way of removing the warning.
  8005. /*
  8006. // Warn if the method is non-const and the object is temporary
  8007. // since the changes will be lost when the object is destroyed.
  8008. // If the object is accessed through a handle, then it is assumed
  8009. // the object is not temporary, even though the handle is.
  8010. if( ctx->type.isTemporary &&
  8011. !ctx->type.dataType.IsObjectHandle() &&
  8012. !engine->scriptFunctions[funcId]->isReadOnly )
  8013. {
  8014. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  8015. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  8016. }
  8017. */ }
  8018. asCByteCode objBC(engine);
  8019. objBC.AddCode(&ctx->bc);
  8020. PrepareFunctionCall(funcId, &ctx->bc, args);
  8021. // Verify if any of the args variable offsets are used in the other code.
  8022. // If they are exchange the offset for a new one
  8023. asUINT n;
  8024. for( n = 0; n < args.GetLength(); n++ )
  8025. {
  8026. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  8027. {
  8028. // Release the current temporary variable
  8029. ReleaseTemporaryVariable(args[n]->type, 0);
  8030. asCDataType dt = args[n]->type.dataType;
  8031. dt.MakeReference(false);
  8032. int l = reservedVariables.GetLength();
  8033. objBC.GetVarsUsed(reservedVariables);
  8034. ctx->bc.GetVarsUsed(reservedVariables);
  8035. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  8036. reservedVariables.SetLength(l);
  8037. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  8038. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  8039. args[n]->type.stackOffset = (short)newOffset;
  8040. args[n]->type.isTemporary = true;
  8041. args[n]->type.isVariable = true;
  8042. }
  8043. }
  8044. #ifndef AS_OLD
  8045. // If the function will return a value type on the stack, then we must allocate space
  8046. // for that here and push the address on the stack as a hidden argument to the function
  8047. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  8048. if( func->DoesReturnOnStack() )
  8049. {
  8050. asASSERT(!useVariable);
  8051. useVariable = true;
  8052. stackOffset = AllocateVariable(func->returnType, true);
  8053. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  8054. }
  8055. #endif
  8056. ctx->bc.AddCode(&objBC);
  8057. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  8058. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  8059. }
  8060. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8061. {
  8062. IsVariableInitialized(&lctx->type, node);
  8063. IsVariableInitialized(&rctx->type, node);
  8064. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  8065. node->tokenType == ttIs || node->tokenType == ttNotIs )
  8066. {
  8067. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  8068. return 0;
  8069. }
  8070. else
  8071. {
  8072. // Compile an overloaded operator for the two operands
  8073. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  8074. return 0;
  8075. // If both operands are objects, then we shouldn't continue
  8076. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  8077. {
  8078. asCString str;
  8079. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  8080. Error(str.AddressOf(), node);
  8081. ctx->type.SetDummy();
  8082. return -1;
  8083. }
  8084. // Process the property get accessors (if any)
  8085. ProcessPropertyGetAccessor(lctx, node);
  8086. ProcessPropertyGetAccessor(rctx, node);
  8087. // Make sure we have two variables or constants
  8088. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  8089. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  8090. // Make sure lctx doesn't end up with a variable used in rctx
  8091. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  8092. {
  8093. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  8094. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  8095. ReleaseTemporaryVariable(offset, 0);
  8096. }
  8097. // Math operators
  8098. // + - * / % += -= *= /= %=
  8099. int op = node->tokenType;
  8100. if( op == ttPlus || op == ttAddAssign ||
  8101. op == ttMinus || op == ttSubAssign ||
  8102. op == ttStar || op == ttMulAssign ||
  8103. op == ttSlash || op == ttDivAssign ||
  8104. op == ttPercent || op == ttModAssign )
  8105. {
  8106. CompileMathOperator(node, lctx, rctx, ctx);
  8107. return 0;
  8108. }
  8109. // Bitwise operators
  8110. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  8111. if( op == ttAmp || op == ttAndAssign ||
  8112. op == ttBitOr || op == ttOrAssign ||
  8113. op == ttBitXor || op == ttXorAssign ||
  8114. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8115. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8116. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8117. {
  8118. CompileBitwiseOperator(node, lctx, rctx, ctx);
  8119. return 0;
  8120. }
  8121. // Comparison operators
  8122. // == != < > <= >=
  8123. if( op == ttEqual || op == ttNotEqual ||
  8124. op == ttLessThan || op == ttLessThanOrEqual ||
  8125. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  8126. {
  8127. CompileComparisonOperator(node, lctx, rctx, ctx);
  8128. return 0;
  8129. }
  8130. // Boolean operators
  8131. // && || ^^
  8132. if( op == ttAnd || op == ttOr || op == ttXor )
  8133. {
  8134. CompileBooleanOperator(node, lctx, rctx, ctx);
  8135. return 0;
  8136. }
  8137. }
  8138. asASSERT(false);
  8139. return -1;
  8140. }
  8141. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  8142. {
  8143. int l = reservedVariables.GetLength();
  8144. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  8145. ConvertToTempVariable(ctx);
  8146. reservedVariables.SetLength(l);
  8147. }
  8148. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  8149. {
  8150. // This is only used for primitive types and null handles
  8151. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  8152. ConvertToVariable(ctx);
  8153. if( !ctx->type.isTemporary )
  8154. {
  8155. if( ctx->type.dataType.IsPrimitive() )
  8156. {
  8157. // Copy the variable to a temporary variable
  8158. int offset = AllocateVariable(ctx->type.dataType, true);
  8159. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8160. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  8161. else
  8162. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  8163. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8164. }
  8165. else
  8166. {
  8167. // We should never get here
  8168. asASSERT(false);
  8169. }
  8170. }
  8171. }
  8172. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  8173. {
  8174. // We should never get here while the context is still an unprocessed property accessor
  8175. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  8176. int offset;
  8177. if( !ctx->type.isVariable &&
  8178. (ctx->type.dataType.IsObjectHandle() ||
  8179. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  8180. {
  8181. offset = AllocateVariable(ctx->type.dataType, true);
  8182. if( ctx->type.IsNullConstant() )
  8183. {
  8184. if( ctx->bc.GetLastInstr() == asBC_PshC4 || ctx->bc.GetLastInstr() == asBC_PshC8 )
  8185. ctx->bc.Pop(AS_PTR_SIZE); // Pop the null constant pushed onto the stack
  8186. #ifdef AS_64BIT_PTR
  8187. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, 0);
  8188. #else
  8189. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, 0);
  8190. #endif
  8191. }
  8192. else
  8193. {
  8194. // Copy the object handle to a variable
  8195. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  8196. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  8197. ctx->bc.Pop(AS_PTR_SIZE);
  8198. }
  8199. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8200. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8201. ctx->type.dataType.MakeHandle(true);
  8202. }
  8203. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  8204. ctx->type.dataType.IsPrimitive() )
  8205. {
  8206. if( ctx->type.isConstant )
  8207. {
  8208. offset = AllocateVariable(ctx->type.dataType, true);
  8209. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8210. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  8211. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8212. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  8213. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  8214. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  8215. else
  8216. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  8217. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8218. return;
  8219. }
  8220. else
  8221. {
  8222. asASSERT(ctx->type.dataType.IsPrimitive());
  8223. asASSERT(ctx->type.dataType.IsReference());
  8224. ctx->type.dataType.MakeReference(false);
  8225. offset = AllocateVariable(ctx->type.dataType, true);
  8226. // Read the value from the address in the register directly into the variable
  8227. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  8228. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  8229. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  8230. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  8231. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8232. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  8233. else
  8234. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  8235. }
  8236. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8237. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  8238. }
  8239. }
  8240. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  8241. {
  8242. int l = reservedVariables.GetLength();
  8243. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  8244. ConvertToVariable(ctx);
  8245. reservedVariables.SetLength(l);
  8246. }
  8247. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8248. {
  8249. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8250. // Implicitly convert the operands to a number type
  8251. asCDataType to;
  8252. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8253. to.SetTokenType(ttDouble);
  8254. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8255. to.SetTokenType(ttFloat);
  8256. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8257. {
  8258. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8259. to.SetTokenType(ttInt64);
  8260. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8261. to.SetTokenType(ttUInt64);
  8262. }
  8263. else
  8264. {
  8265. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8266. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8267. to.SetTokenType(ttInt);
  8268. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8269. to.SetTokenType(ttUInt);
  8270. }
  8271. // If doing an operation with double constant and float variable, the constant should be converted to float
  8272. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8273. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8274. to.SetTokenType(ttFloat);
  8275. // Do the actual conversion
  8276. int l = reservedVariables.GetLength();
  8277. rctx->bc.GetVarsUsed(reservedVariables);
  8278. lctx->bc.GetVarsUsed(reservedVariables);
  8279. if( lctx->type.dataType.IsReference() )
  8280. ConvertToVariable(lctx);
  8281. if( rctx->type.dataType.IsReference() )
  8282. ConvertToVariable(rctx);
  8283. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8284. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  8285. reservedVariables.SetLength(l);
  8286. // Verify that the conversion was successful
  8287. if( !lctx->type.dataType.IsIntegerType() &&
  8288. !lctx->type.dataType.IsUnsignedType() &&
  8289. !lctx->type.dataType.IsFloatType() &&
  8290. !lctx->type.dataType.IsDoubleType() )
  8291. {
  8292. asCString str;
  8293. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  8294. Error(str.AddressOf(), node);
  8295. ctx->type.SetDummy();
  8296. return;
  8297. }
  8298. if( !rctx->type.dataType.IsIntegerType() &&
  8299. !rctx->type.dataType.IsUnsignedType() &&
  8300. !rctx->type.dataType.IsFloatType() &&
  8301. !rctx->type.dataType.IsDoubleType() )
  8302. {
  8303. asCString str;
  8304. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  8305. Error(str.AddressOf(), node);
  8306. ctx->type.SetDummy();
  8307. return;
  8308. }
  8309. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8310. // Verify if we are dividing with a constant zero
  8311. int op = node->tokenType;
  8312. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  8313. (op == ttSlash || op == ttDivAssign ||
  8314. op == ttPercent || op == ttModAssign) )
  8315. {
  8316. Error(TXT_DIVIDE_BY_ZERO, node);
  8317. }
  8318. if( !isConstant )
  8319. {
  8320. ConvertToVariableNotIn(lctx, rctx);
  8321. ConvertToVariableNotIn(rctx, lctx);
  8322. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8323. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8324. if( op == ttAddAssign || op == ttSubAssign ||
  8325. op == ttMulAssign || op == ttDivAssign ||
  8326. op == ttModAssign )
  8327. {
  8328. // Merge the operands in the different order so that they are evaluated correctly
  8329. MergeExprBytecode(ctx, rctx);
  8330. MergeExprBytecode(ctx, lctx);
  8331. }
  8332. else
  8333. {
  8334. MergeExprBytecode(ctx, lctx);
  8335. MergeExprBytecode(ctx, rctx);
  8336. }
  8337. ProcessDeferredParams(ctx);
  8338. asEBCInstr instruction = asBC_ADDi;
  8339. if( lctx->type.dataType.IsIntegerType() ||
  8340. lctx->type.dataType.IsUnsignedType() )
  8341. {
  8342. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8343. {
  8344. if( op == ttPlus || op == ttAddAssign )
  8345. instruction = asBC_ADDi;
  8346. else if( op == ttMinus || op == ttSubAssign )
  8347. instruction = asBC_SUBi;
  8348. else if( op == ttStar || op == ttMulAssign )
  8349. instruction = asBC_MULi;
  8350. else if( op == ttSlash || op == ttDivAssign )
  8351. {
  8352. if( lctx->type.dataType.IsIntegerType() )
  8353. instruction = asBC_DIVi;
  8354. else
  8355. instruction = asBC_DIVu;
  8356. }
  8357. else if( op == ttPercent || op == ttModAssign )
  8358. {
  8359. if( lctx->type.dataType.IsIntegerType() )
  8360. instruction = asBC_MODi;
  8361. else
  8362. instruction = asBC_MODu;
  8363. }
  8364. }
  8365. else
  8366. {
  8367. if( op == ttPlus || op == ttAddAssign )
  8368. instruction = asBC_ADDi64;
  8369. else if( op == ttMinus || op == ttSubAssign )
  8370. instruction = asBC_SUBi64;
  8371. else if( op == ttStar || op == ttMulAssign )
  8372. instruction = asBC_MULi64;
  8373. else if( op == ttSlash || op == ttDivAssign )
  8374. {
  8375. if( lctx->type.dataType.IsIntegerType() )
  8376. instruction = asBC_DIVi64;
  8377. else
  8378. instruction = asBC_DIVu64;
  8379. }
  8380. else if( op == ttPercent || op == ttModAssign )
  8381. {
  8382. if( lctx->type.dataType.IsIntegerType() )
  8383. instruction = asBC_MODi64;
  8384. else
  8385. instruction = asBC_MODu64;
  8386. }
  8387. }
  8388. }
  8389. else if( lctx->type.dataType.IsFloatType() )
  8390. {
  8391. if( op == ttPlus || op == ttAddAssign )
  8392. instruction = asBC_ADDf;
  8393. else if( op == ttMinus || op == ttSubAssign )
  8394. instruction = asBC_SUBf;
  8395. else if( op == ttStar || op == ttMulAssign )
  8396. instruction = asBC_MULf;
  8397. else if( op == ttSlash || op == ttDivAssign )
  8398. instruction = asBC_DIVf;
  8399. else if( op == ttPercent || op == ttModAssign )
  8400. instruction = asBC_MODf;
  8401. }
  8402. else if( lctx->type.dataType.IsDoubleType() )
  8403. {
  8404. if( op == ttPlus || op == ttAddAssign )
  8405. instruction = asBC_ADDd;
  8406. else if( op == ttMinus || op == ttSubAssign )
  8407. instruction = asBC_SUBd;
  8408. else if( op == ttStar || op == ttMulAssign )
  8409. instruction = asBC_MULd;
  8410. else if( op == ttSlash || op == ttDivAssign )
  8411. instruction = asBC_DIVd;
  8412. else if( op == ttPercent || op == ttModAssign )
  8413. instruction = asBC_MODd;
  8414. }
  8415. else
  8416. {
  8417. // Shouldn't be possible
  8418. asASSERT(false);
  8419. }
  8420. // Do the operation
  8421. int a = AllocateVariable(lctx->type.dataType, true);
  8422. int b = lctx->type.stackOffset;
  8423. int c = rctx->type.stackOffset;
  8424. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8425. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8426. }
  8427. else
  8428. {
  8429. // Both values are constants
  8430. if( lctx->type.dataType.IsIntegerType() ||
  8431. lctx->type.dataType.IsUnsignedType() )
  8432. {
  8433. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8434. {
  8435. int v = 0;
  8436. if( op == ttPlus )
  8437. v = lctx->type.intValue + rctx->type.intValue;
  8438. else if( op == ttMinus )
  8439. v = lctx->type.intValue - rctx->type.intValue;
  8440. else if( op == ttStar )
  8441. v = lctx->type.intValue * rctx->type.intValue;
  8442. else if( op == ttSlash )
  8443. {
  8444. if( rctx->type.intValue == 0 )
  8445. v = 0;
  8446. else
  8447. if( lctx->type.dataType.IsIntegerType() )
  8448. v = lctx->type.intValue / rctx->type.intValue;
  8449. else
  8450. v = lctx->type.dwordValue / rctx->type.dwordValue;
  8451. }
  8452. else if( op == ttPercent )
  8453. {
  8454. if( rctx->type.intValue == 0 )
  8455. v = 0;
  8456. else
  8457. if( lctx->type.dataType.IsIntegerType() )
  8458. v = lctx->type.intValue % rctx->type.intValue;
  8459. else
  8460. v = lctx->type.dwordValue % rctx->type.dwordValue;
  8461. }
  8462. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8463. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8464. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  8465. ctx->type.dataType.SetTokenType(ttInt);
  8466. }
  8467. else
  8468. {
  8469. asQWORD v = 0;
  8470. if( op == ttPlus )
  8471. v = lctx->type.qwordValue + rctx->type.qwordValue;
  8472. else if( op == ttMinus )
  8473. v = lctx->type.qwordValue - rctx->type.qwordValue;
  8474. else if( op == ttStar )
  8475. v = lctx->type.qwordValue * rctx->type.qwordValue;
  8476. else if( op == ttSlash )
  8477. {
  8478. if( rctx->type.qwordValue == 0 )
  8479. v = 0;
  8480. else
  8481. if( lctx->type.dataType.IsIntegerType() )
  8482. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  8483. else
  8484. v = lctx->type.qwordValue / rctx->type.qwordValue;
  8485. }
  8486. else if( op == ttPercent )
  8487. {
  8488. if( rctx->type.qwordValue == 0 )
  8489. v = 0;
  8490. else
  8491. if( lctx->type.dataType.IsIntegerType() )
  8492. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  8493. else
  8494. v = lctx->type.qwordValue % rctx->type.qwordValue;
  8495. }
  8496. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8497. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8498. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  8499. ctx->type.dataType.SetTokenType(ttInt64);
  8500. }
  8501. }
  8502. else if( lctx->type.dataType.IsFloatType() )
  8503. {
  8504. float v = 0.0f;
  8505. if( op == ttPlus )
  8506. v = lctx->type.floatValue + rctx->type.floatValue;
  8507. else if( op == ttMinus )
  8508. v = lctx->type.floatValue - rctx->type.floatValue;
  8509. else if( op == ttStar )
  8510. v = lctx->type.floatValue * rctx->type.floatValue;
  8511. else if( op == ttSlash )
  8512. {
  8513. if( rctx->type.floatValue == 0 )
  8514. v = 0;
  8515. else
  8516. v = lctx->type.floatValue / rctx->type.floatValue;
  8517. }
  8518. else if( op == ttPercent )
  8519. {
  8520. if( rctx->type.floatValue == 0 )
  8521. v = 0;
  8522. else
  8523. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  8524. }
  8525. ctx->type.SetConstantF(lctx->type.dataType, v);
  8526. }
  8527. else if( lctx->type.dataType.IsDoubleType() )
  8528. {
  8529. double v = 0.0;
  8530. if( op == ttPlus )
  8531. v = lctx->type.doubleValue + rctx->type.doubleValue;
  8532. else if( op == ttMinus )
  8533. v = lctx->type.doubleValue - rctx->type.doubleValue;
  8534. else if( op == ttStar )
  8535. v = lctx->type.doubleValue * rctx->type.doubleValue;
  8536. else if( op == ttSlash )
  8537. {
  8538. if( rctx->type.doubleValue == 0 )
  8539. v = 0;
  8540. else
  8541. v = lctx->type.doubleValue / rctx->type.doubleValue;
  8542. }
  8543. else if( op == ttPercent )
  8544. {
  8545. if( rctx->type.doubleValue == 0 )
  8546. v = 0;
  8547. else
  8548. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  8549. }
  8550. ctx->type.SetConstantD(lctx->type.dataType, v);
  8551. }
  8552. else
  8553. {
  8554. // Shouldn't be possible
  8555. asASSERT(false);
  8556. }
  8557. }
  8558. }
  8559. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8560. {
  8561. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8562. int op = node->tokenType;
  8563. if( op == ttAmp || op == ttAndAssign ||
  8564. op == ttBitOr || op == ttOrAssign ||
  8565. op == ttBitXor || op == ttXorAssign )
  8566. {
  8567. // Convert left hand operand to integer if it's not already one
  8568. asCDataType to;
  8569. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  8570. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8571. to.SetTokenType(ttUInt64);
  8572. else
  8573. to.SetTokenType(ttUInt);
  8574. // Do the actual conversion
  8575. int l = reservedVariables.GetLength();
  8576. rctx->bc.GetVarsUsed(reservedVariables);
  8577. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8578. reservedVariables.SetLength(l);
  8579. // Verify that the conversion was successful
  8580. if( !lctx->type.dataType.IsUnsignedType() )
  8581. {
  8582. asCString str;
  8583. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8584. Error(str.AddressOf(), node);
  8585. }
  8586. // Convert right hand operand to same type as left hand operand
  8587. l = reservedVariables.GetLength();
  8588. lctx->bc.GetVarsUsed(reservedVariables);
  8589. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true);
  8590. reservedVariables.SetLength(l);
  8591. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  8592. {
  8593. asCString str;
  8594. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  8595. Error(str.AddressOf(), node);
  8596. }
  8597. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8598. if( !isConstant )
  8599. {
  8600. ConvertToVariableNotIn(lctx, rctx);
  8601. ConvertToVariableNotIn(rctx, lctx);
  8602. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8603. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8604. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  8605. {
  8606. // Compound assignments execute the right hand value first
  8607. MergeExprBytecode(ctx, rctx);
  8608. MergeExprBytecode(ctx, lctx);
  8609. }
  8610. else
  8611. {
  8612. MergeExprBytecode(ctx, lctx);
  8613. MergeExprBytecode(ctx, rctx);
  8614. }
  8615. ProcessDeferredParams(ctx);
  8616. asEBCInstr instruction = asBC_BAND;
  8617. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8618. {
  8619. if( op == ttAmp || op == ttAndAssign )
  8620. instruction = asBC_BAND;
  8621. else if( op == ttBitOr || op == ttOrAssign )
  8622. instruction = asBC_BOR;
  8623. else if( op == ttBitXor || op == ttXorAssign )
  8624. instruction = asBC_BXOR;
  8625. }
  8626. else
  8627. {
  8628. if( op == ttAmp || op == ttAndAssign )
  8629. instruction = asBC_BAND64;
  8630. else if( op == ttBitOr || op == ttOrAssign )
  8631. instruction = asBC_BOR64;
  8632. else if( op == ttBitXor || op == ttXorAssign )
  8633. instruction = asBC_BXOR64;
  8634. }
  8635. // Do the operation
  8636. int a = AllocateVariable(lctx->type.dataType, true);
  8637. int b = lctx->type.stackOffset;
  8638. int c = rctx->type.stackOffset;
  8639. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8640. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8641. }
  8642. else
  8643. {
  8644. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8645. {
  8646. asQWORD v = 0;
  8647. if( op == ttAmp )
  8648. v = lctx->type.qwordValue & rctx->type.qwordValue;
  8649. else if( op == ttBitOr )
  8650. v = lctx->type.qwordValue | rctx->type.qwordValue;
  8651. else if( op == ttBitXor )
  8652. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  8653. // Remember the result
  8654. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8655. }
  8656. else
  8657. {
  8658. asDWORD v = 0;
  8659. if( op == ttAmp )
  8660. v = lctx->type.dwordValue & rctx->type.dwordValue;
  8661. else if( op == ttBitOr )
  8662. v = lctx->type.dwordValue | rctx->type.dwordValue;
  8663. else if( op == ttBitXor )
  8664. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  8665. // Remember the result
  8666. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8667. }
  8668. }
  8669. }
  8670. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8671. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8672. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8673. {
  8674. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  8675. if( lctx->type.dataType.IsObject() )
  8676. {
  8677. asCString str;
  8678. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  8679. Error(str.AddressOf(), node);
  8680. // Set an integer value and allow the compiler to continue
  8681. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  8682. return;
  8683. }
  8684. // Convert left hand operand to integer if it's not already one
  8685. asCDataType to = lctx->type.dataType;
  8686. if( lctx->type.dataType.IsUnsignedType() &&
  8687. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  8688. {
  8689. to = asCDataType::CreatePrimitive(ttUInt, false);
  8690. }
  8691. else if( !lctx->type.dataType.IsUnsignedType() )
  8692. {
  8693. asCDataType to;
  8694. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8695. to.SetTokenType(ttInt64);
  8696. else
  8697. to.SetTokenType(ttInt);
  8698. }
  8699. // Do the actual conversion
  8700. int l = reservedVariables.GetLength();
  8701. rctx->bc.GetVarsUsed(reservedVariables);
  8702. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  8703. reservedVariables.SetLength(l);
  8704. // Verify that the conversion was successful
  8705. if( lctx->type.dataType != to )
  8706. {
  8707. asCString str;
  8708. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8709. Error(str.AddressOf(), node);
  8710. }
  8711. // Right operand must be 32bit uint
  8712. l = reservedVariables.GetLength();
  8713. lctx->bc.GetVarsUsed(reservedVariables);
  8714. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  8715. reservedVariables.SetLength(l);
  8716. if( !rctx->type.dataType.IsUnsignedType() )
  8717. {
  8718. asCString str;
  8719. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  8720. Error(str.AddressOf(), node);
  8721. }
  8722. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8723. if( !isConstant )
  8724. {
  8725. ConvertToVariableNotIn(lctx, rctx);
  8726. ConvertToVariableNotIn(rctx, lctx);
  8727. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8728. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8729. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  8730. {
  8731. // Compound assignments execute the right hand value first
  8732. MergeExprBytecode(ctx, rctx);
  8733. MergeExprBytecode(ctx, lctx);
  8734. }
  8735. else
  8736. {
  8737. MergeExprBytecode(ctx, lctx);
  8738. MergeExprBytecode(ctx, rctx);
  8739. }
  8740. ProcessDeferredParams(ctx);
  8741. asEBCInstr instruction = asBC_BSLL;
  8742. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8743. {
  8744. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8745. instruction = asBC_BSLL;
  8746. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8747. instruction = asBC_BSRL;
  8748. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8749. instruction = asBC_BSRA;
  8750. }
  8751. else
  8752. {
  8753. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8754. instruction = asBC_BSLL64;
  8755. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8756. instruction = asBC_BSRL64;
  8757. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8758. instruction = asBC_BSRA64;
  8759. }
  8760. // Do the operation
  8761. int a = AllocateVariable(lctx->type.dataType, true);
  8762. int b = lctx->type.stackOffset;
  8763. int c = rctx->type.stackOffset;
  8764. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8765. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8766. }
  8767. else
  8768. {
  8769. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8770. {
  8771. asDWORD v = 0;
  8772. if( op == ttBitShiftLeft )
  8773. v = lctx->type.dwordValue << rctx->type.dwordValue;
  8774. else if( op == ttBitShiftRight )
  8775. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  8776. else if( op == ttBitShiftRightArith )
  8777. v = lctx->type.intValue >> rctx->type.dwordValue;
  8778. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8779. }
  8780. else
  8781. {
  8782. asQWORD v = 0;
  8783. if( op == ttBitShiftLeft )
  8784. v = lctx->type.qwordValue << rctx->type.dwordValue;
  8785. else if( op == ttBitShiftRight )
  8786. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  8787. else if( op == ttBitShiftRightArith )
  8788. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  8789. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8790. }
  8791. }
  8792. }
  8793. }
  8794. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8795. {
  8796. // Both operands must be of the same type
  8797. // Implicitly convert the operands to a number type
  8798. asCDataType to;
  8799. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8800. to.SetTokenType(ttDouble);
  8801. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8802. to.SetTokenType(ttFloat);
  8803. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8804. {
  8805. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8806. to.SetTokenType(ttInt64);
  8807. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8808. to.SetTokenType(ttUInt64);
  8809. }
  8810. else
  8811. {
  8812. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8813. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8814. to.SetTokenType(ttInt);
  8815. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8816. to.SetTokenType(ttUInt);
  8817. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  8818. to.SetTokenType(ttBool);
  8819. }
  8820. // If doing an operation with double constant and float variable, the constant should be converted to float
  8821. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8822. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8823. to.SetTokenType(ttFloat);
  8824. // Is it an operation on signed values?
  8825. bool signMismatch = false;
  8826. if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
  8827. {
  8828. if( lctx->type.dataType.GetTokenType() == ttUInt64 )
  8829. {
  8830. if( !lctx->type.isConstant )
  8831. signMismatch = true;
  8832. else if( lctx->type.qwordValue & (I64(1)<<63) )
  8833. signMismatch = true;
  8834. }
  8835. if( lctx->type.dataType.GetTokenType() == ttUInt )
  8836. {
  8837. if( !lctx->type.isConstant )
  8838. signMismatch = true;
  8839. else if( lctx->type.dwordValue & (1<<31) )
  8840. signMismatch = true;
  8841. }
  8842. if( rctx->type.dataType.GetTokenType() == ttUInt64 )
  8843. {
  8844. if( !rctx->type.isConstant )
  8845. signMismatch = true;
  8846. else if( rctx->type.qwordValue & (I64(1)<<63) )
  8847. signMismatch = true;
  8848. }
  8849. if( rctx->type.dataType.GetTokenType() == ttUInt )
  8850. {
  8851. if( !rctx->type.isConstant )
  8852. signMismatch = true;
  8853. else if( rctx->type.dwordValue & (1<<31) )
  8854. signMismatch = true;
  8855. }
  8856. }
  8857. // Check for signed/unsigned mismatch
  8858. if( signMismatch )
  8859. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  8860. // Do the actual conversion
  8861. int l = reservedVariables.GetLength();
  8862. rctx->bc.GetVarsUsed(reservedVariables);
  8863. if( lctx->type.dataType.IsReference() )
  8864. ConvertToVariable(lctx);
  8865. if( rctx->type.dataType.IsReference() )
  8866. ConvertToVariable(rctx);
  8867. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  8868. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8869. reservedVariables.SetLength(l);
  8870. // Verify that the conversion was successful
  8871. bool ok = true;
  8872. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8873. {
  8874. asCString str;
  8875. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8876. Error(str.AddressOf(), node);
  8877. ok = false;
  8878. }
  8879. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8880. {
  8881. asCString str;
  8882. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8883. Error(str.AddressOf(), node);
  8884. ok = false;
  8885. }
  8886. if( !ok )
  8887. {
  8888. // It wasn't possible to get two valid operands, so we just return
  8889. // a boolean result and let the compiler continue.
  8890. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8891. return;
  8892. }
  8893. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8894. int op = node->tokenType;
  8895. if( !isConstant )
  8896. {
  8897. if( to.IsBooleanType() )
  8898. {
  8899. int op = node->tokenType;
  8900. if( op == ttEqual || op == ttNotEqual )
  8901. {
  8902. // Must convert to temporary variable, because we are changing the value before comparison
  8903. ConvertToTempVariableNotIn(lctx, rctx);
  8904. ConvertToTempVariableNotIn(rctx, lctx);
  8905. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8906. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8907. // Make sure they are equal if not false
  8908. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8909. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8910. MergeExprBytecode(ctx, lctx);
  8911. MergeExprBytecode(ctx, rctx);
  8912. ProcessDeferredParams(ctx);
  8913. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8914. int b = lctx->type.stackOffset;
  8915. int c = rctx->type.stackOffset;
  8916. if( op == ttEqual )
  8917. {
  8918. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8919. ctx->bc.Instr(asBC_TZ);
  8920. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8921. }
  8922. else if( op == ttNotEqual )
  8923. {
  8924. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8925. ctx->bc.Instr(asBC_TNZ);
  8926. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8927. }
  8928. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8929. }
  8930. else
  8931. {
  8932. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8933. Error(TXT_ILLEGAL_OPERATION, node);
  8934. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  8935. }
  8936. }
  8937. else
  8938. {
  8939. ConvertToVariableNotIn(lctx, rctx);
  8940. ConvertToVariableNotIn(rctx, lctx);
  8941. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8942. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8943. MergeExprBytecode(ctx, lctx);
  8944. MergeExprBytecode(ctx, rctx);
  8945. ProcessDeferredParams(ctx);
  8946. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  8947. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8948. iCmp = asBC_CMPi;
  8949. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8950. iCmp = asBC_CMPu;
  8951. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8952. iCmp = asBC_CMPi64;
  8953. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8954. iCmp = asBC_CMPu64;
  8955. else if( lctx->type.dataType.IsFloatType() )
  8956. iCmp = asBC_CMPf;
  8957. else if( lctx->type.dataType.IsDoubleType() )
  8958. iCmp = asBC_CMPd;
  8959. else
  8960. asASSERT(false);
  8961. if( op == ttEqual )
  8962. iT = asBC_TZ;
  8963. else if( op == ttNotEqual )
  8964. iT = asBC_TNZ;
  8965. else if( op == ttLessThan )
  8966. iT = asBC_TS;
  8967. else if( op == ttLessThanOrEqual )
  8968. iT = asBC_TNP;
  8969. else if( op == ttGreaterThan )
  8970. iT = asBC_TP;
  8971. else if( op == ttGreaterThanOrEqual )
  8972. iT = asBC_TNS;
  8973. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8974. int b = lctx->type.stackOffset;
  8975. int c = rctx->type.stackOffset;
  8976. ctx->bc.InstrW_W(iCmp, b, c);
  8977. ctx->bc.Instr(iT);
  8978. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8979. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8980. }
  8981. }
  8982. else
  8983. {
  8984. if( to.IsBooleanType() )
  8985. {
  8986. int op = node->tokenType;
  8987. if( op == ttEqual || op == ttNotEqual )
  8988. {
  8989. // Make sure they are equal if not false
  8990. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8991. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8992. asDWORD v = 0;
  8993. if( op == ttEqual )
  8994. {
  8995. v = lctx->type.intValue - rctx->type.intValue;
  8996. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8997. }
  8998. else if( op == ttNotEqual )
  8999. {
  9000. v = lctx->type.intValue - rctx->type.intValue;
  9001. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9002. }
  9003. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  9004. }
  9005. else
  9006. {
  9007. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9008. Error(TXT_ILLEGAL_OPERATION, node);
  9009. }
  9010. }
  9011. else
  9012. {
  9013. int i = 0;
  9014. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9015. {
  9016. int v = lctx->type.intValue - rctx->type.intValue;
  9017. if( v < 0 ) i = -1;
  9018. if( v > 0 ) i = 1;
  9019. }
  9020. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9021. {
  9022. asDWORD v1 = lctx->type.dwordValue;
  9023. asDWORD v2 = rctx->type.dwordValue;
  9024. if( v1 < v2 ) i = -1;
  9025. if( v1 > v2 ) i = 1;
  9026. }
  9027. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9028. {
  9029. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  9030. if( v < 0 ) i = -1;
  9031. if( v > 0 ) i = 1;
  9032. }
  9033. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9034. {
  9035. asQWORD v1 = lctx->type.qwordValue;
  9036. asQWORD v2 = rctx->type.qwordValue;
  9037. if( v1 < v2 ) i = -1;
  9038. if( v1 > v2 ) i = 1;
  9039. }
  9040. else if( lctx->type.dataType.IsFloatType() )
  9041. {
  9042. float v = lctx->type.floatValue - rctx->type.floatValue;
  9043. if( v < 0 ) i = -1;
  9044. if( v > 0 ) i = 1;
  9045. }
  9046. else if( lctx->type.dataType.IsDoubleType() )
  9047. {
  9048. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  9049. if( v < 0 ) i = -1;
  9050. if( v > 0 ) i = 1;
  9051. }
  9052. if( op == ttEqual )
  9053. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9054. else if( op == ttNotEqual )
  9055. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9056. else if( op == ttLessThan )
  9057. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9058. else if( op == ttLessThanOrEqual )
  9059. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9060. else if( op == ttGreaterThan )
  9061. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9062. else if( op == ttGreaterThanOrEqual )
  9063. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9064. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  9065. }
  9066. }
  9067. }
  9068. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  9069. {
  9070. // Put the result on the stack
  9071. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  9072. if( asReference )
  9073. ctx->type.dataType.MakeReference(true);
  9074. else
  9075. {
  9076. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9077. ctx->bc.Instr(asBC_RDS4);
  9078. else
  9079. ctx->bc.Instr(asBC_RDS8);
  9080. }
  9081. }
  9082. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9083. {
  9084. // Both operands must be booleans
  9085. asCDataType to;
  9086. to.SetTokenType(ttBool);
  9087. // Do the actual conversion
  9088. int l = reservedVariables.GetLength();
  9089. rctx->bc.GetVarsUsed(reservedVariables);
  9090. lctx->bc.GetVarsUsed(reservedVariables);
  9091. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9092. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9093. reservedVariables.SetLength(l);
  9094. // Verify that the conversion was successful
  9095. if( !lctx->type.dataType.IsBooleanType() )
  9096. {
  9097. asCString str;
  9098. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  9099. Error(str.AddressOf(), node);
  9100. // Force the conversion to allow compilation to proceed
  9101. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  9102. }
  9103. if( !rctx->type.dataType.IsBooleanType() )
  9104. {
  9105. asCString str;
  9106. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  9107. Error(str.AddressOf(), node);
  9108. // Force the conversion to allow compilation to proceed
  9109. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  9110. }
  9111. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9112. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  9113. // What kind of operator is it?
  9114. int op = node->tokenType;
  9115. if( op == ttXor )
  9116. {
  9117. if( !isConstant )
  9118. {
  9119. // Must convert to temporary variable, because we are changing the value before comparison
  9120. ConvertToTempVariableNotIn(lctx, rctx);
  9121. ConvertToTempVariableNotIn(rctx, lctx);
  9122. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9123. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9124. // Make sure they are equal if not false
  9125. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  9126. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  9127. MergeExprBytecode(ctx, lctx);
  9128. MergeExprBytecode(ctx, rctx);
  9129. ProcessDeferredParams(ctx);
  9130. int a = AllocateVariable(ctx->type.dataType, true);
  9131. int b = lctx->type.stackOffset;
  9132. int c = rctx->type.stackOffset;
  9133. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  9134. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9135. }
  9136. else
  9137. {
  9138. // Make sure they are equal if not false
  9139. #if AS_SIZEOF_BOOL == 1
  9140. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  9141. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  9142. asBYTE v = 0;
  9143. v = lctx->type.byteValue - rctx->type.byteValue;
  9144. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9145. ctx->type.isConstant = true;
  9146. ctx->type.byteValue = v;
  9147. #else
  9148. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9149. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9150. asDWORD v = 0;
  9151. v = lctx->type.intValue - rctx->type.intValue;
  9152. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9153. ctx->type.isConstant = true;
  9154. ctx->type.dwordValue = v;
  9155. #endif
  9156. }
  9157. }
  9158. else if( op == ttAnd ||
  9159. op == ttOr )
  9160. {
  9161. if( !isConstant )
  9162. {
  9163. // If or-operator and first value is 1 the second value shouldn't be calculated
  9164. // if and-operator and first value is 0 the second value shouldn't be calculated
  9165. ConvertToVariable(lctx);
  9166. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9167. MergeExprBytecode(ctx, lctx);
  9168. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  9169. int label1 = nextLabel++;
  9170. int label2 = nextLabel++;
  9171. if( op == ttAnd )
  9172. {
  9173. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9174. ctx->bc.Instr(asBC_ClrHi);
  9175. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  9176. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  9177. ctx->bc.InstrINT(asBC_JMP, label2);
  9178. }
  9179. else if( op == ttOr )
  9180. {
  9181. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  9182. ctx->bc.Instr(asBC_ClrHi);
  9183. ctx->bc.InstrDWORD(asBC_JZ, label1);
  9184. #if AS_SIZEOF_BOOL == 1
  9185. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9186. #else
  9187. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  9188. #endif
  9189. ctx->bc.InstrINT(asBC_JMP, label2);
  9190. }
  9191. ctx->bc.Label((short)label1);
  9192. ConvertToVariable(rctx);
  9193. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9194. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  9195. MergeExprBytecode(ctx, rctx);
  9196. ctx->bc.Label((short)label2);
  9197. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  9198. }
  9199. else
  9200. {
  9201. #if AS_SIZEOF_BOOL == 1
  9202. asBYTE v = 0;
  9203. if( op == ttAnd )
  9204. v = lctx->type.byteValue && rctx->type.byteValue;
  9205. else if( op == ttOr )
  9206. v = lctx->type.byteValue || rctx->type.byteValue;
  9207. // Remember the result
  9208. ctx->type.isConstant = true;
  9209. ctx->type.byteValue = v;
  9210. #else
  9211. asDWORD v = 0;
  9212. if( op == ttAnd )
  9213. v = lctx->type.dwordValue && rctx->type.dwordValue;
  9214. else if( op == ttOr )
  9215. v = lctx->type.dwordValue || rctx->type.dwordValue;
  9216. // Remember the result
  9217. ctx->type.isConstant = true;
  9218. ctx->type.dwordValue = v;
  9219. #endif
  9220. }
  9221. }
  9222. }
  9223. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9224. {
  9225. // Process the property accessor as get
  9226. ProcessPropertyGetAccessor(lctx, node);
  9227. ProcessPropertyGetAccessor(rctx, node);
  9228. // Make sure lctx doesn't end up with a variable used in rctx
  9229. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9230. {
  9231. asCArray<int> vars;
  9232. rctx->bc.GetVarsUsed(vars);
  9233. int offset = AllocateVariable(lctx->type.dataType, true);
  9234. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9235. ReleaseTemporaryVariable(offset, 0);
  9236. }
  9237. // Warn if not both operands are explicit handles
  9238. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  9239. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  9240. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  9241. {
  9242. Warning(TXT_HANDLE_COMPARISON, node);
  9243. }
  9244. // If one of the operands is a value type used as handle, we should look for the opEquals method
  9245. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  9246. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  9247. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  9248. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  9249. {
  9250. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  9251. // Find the matching opEquals method
  9252. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9253. if( r == 0 )
  9254. {
  9255. // Try again by switching the order of the operands
  9256. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  9257. }
  9258. if( r == 1 )
  9259. {
  9260. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  9261. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9262. // Success, don't continue
  9263. return;
  9264. }
  9265. else if( r == 0 )
  9266. {
  9267. // Couldn't find opEquals method
  9268. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  9269. }
  9270. // Compiler error, don't continue
  9271. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9272. return;
  9273. }
  9274. // Implicitly convert null to the other type
  9275. asCDataType to;
  9276. if( lctx->type.IsNullConstant() )
  9277. to = rctx->type.dataType;
  9278. else if( rctx->type.IsNullConstant() )
  9279. to = lctx->type.dataType;
  9280. else
  9281. {
  9282. // TODO: Use the common base type
  9283. to = lctx->type.dataType;
  9284. }
  9285. // Need to pop the value if it is a null constant
  9286. if( lctx->type.IsNullConstant() )
  9287. lctx->bc.Pop(AS_PTR_SIZE);
  9288. if( rctx->type.IsNullConstant() )
  9289. rctx->bc.Pop(AS_PTR_SIZE);
  9290. // Convert both sides to explicit handles
  9291. to.MakeHandle(true);
  9292. to.MakeReference(false);
  9293. // Do the conversion
  9294. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9295. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9296. // Both operands must be of the same type
  9297. // Verify that the conversion was successful
  9298. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  9299. {
  9300. asCString str;
  9301. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9302. Error(str.AddressOf(), node);
  9303. }
  9304. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  9305. {
  9306. asCString str;
  9307. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9308. Error(str.AddressOf(), node);
  9309. }
  9310. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  9311. int op = node->tokenType;
  9312. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  9313. {
  9314. // If the object handle already is in a variable we must manually pop it from the stack
  9315. if( lctx->type.isVariable )
  9316. lctx->bc.Pop(AS_PTR_SIZE);
  9317. if( rctx->type.isVariable )
  9318. rctx->bc.Pop(AS_PTR_SIZE);
  9319. // TODO: optimize: Treat the object handles as two integers, i.e. don't do REFCPY
  9320. ConvertToVariableNotIn(lctx, rctx);
  9321. ConvertToVariable(rctx);
  9322. MergeExprBytecode(ctx, lctx);
  9323. MergeExprBytecode(ctx, rctx);
  9324. int a = AllocateVariable(ctx->type.dataType, true);
  9325. int b = lctx->type.stackOffset;
  9326. int c = rctx->type.stackOffset;
  9327. // TODO: When saving the bytecode we must be able to determine that this is
  9328. // a comparison with a pointer, so that the instruction can be adapted
  9329. // to the pointer size on the platform that will execute it.
  9330. #ifdef AS_64BIT_PTR
  9331. ctx->bc.InstrW_W(asBC_CMPi64, b, c);
  9332. #else
  9333. ctx->bc.InstrW_W(asBC_CMPi, b, c);
  9334. #endif
  9335. if( op == ttEqual || op == ttIs )
  9336. ctx->bc.Instr(asBC_TZ);
  9337. else if( op == ttNotEqual || op == ttNotIs )
  9338. ctx->bc.Instr(asBC_TNZ);
  9339. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9340. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9341. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  9342. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  9343. ProcessDeferredParams(ctx);
  9344. }
  9345. else
  9346. {
  9347. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9348. Error(TXT_ILLEGAL_OPERATION, node);
  9349. }
  9350. }
  9351. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  9352. {
  9353. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  9354. // A shared object may not call non-shared functions
  9355. if( outFunc->objectType && outFunc->objectType->IsShared() && !descr->IsShared() )
  9356. {
  9357. asCString msg;
  9358. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  9359. Error(msg.AddressOf(), ctx->exprNode);
  9360. }
  9361. // Check if the function is private
  9362. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  9363. {
  9364. asCString msg;
  9365. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  9366. Error(msg.AddressOf(), ctx->exprNode);
  9367. }
  9368. int argSize = descr->GetSpaceNeededForArguments();
  9369. if( descr->objectType && descr->returnType.IsReference() &&
  9370. !ctx->type.isVariable && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  9371. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  9372. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  9373. {
  9374. // The class method we're calling is returning a reference, which may be to a member of the object.
  9375. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  9376. // TODO: optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  9377. int tempRef = AllocateVariable(ctx->type.dataType, true);
  9378. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  9379. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9380. // Add the release of this reference, as a deferred expression
  9381. asSDeferredParam deferred;
  9382. deferred.origExpr = 0;
  9383. deferred.argInOutFlags = asTM_INREF;
  9384. deferred.argNode = 0;
  9385. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  9386. ctx->deferredParams.PushLast(deferred);
  9387. // Forget the current type
  9388. ctx->type.SetDummy();
  9389. }
  9390. if( isConstructor )
  9391. {
  9392. // Sometimes the value types are allocated on the heap,
  9393. // which is when this way of constructing them is used.
  9394. asASSERT(useVariable == false);
  9395. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  9396. // The instruction has already moved the returned object to the variable
  9397. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  9398. ctx->type.isLValue = false;
  9399. // Clean up arguments
  9400. if( args )
  9401. AfterFunctionCall(funcId, *args, ctx, false);
  9402. ProcessDeferredParams(ctx);
  9403. return;
  9404. }
  9405. else
  9406. {
  9407. if( descr->objectType )
  9408. argSize += AS_PTR_SIZE;
  9409. #ifndef AS_OLD
  9410. // If the function returns an object by value the address of the location
  9411. // where the value should be stored is passed as an argument too
  9412. if( descr->DoesReturnOnStack() )
  9413. {
  9414. argSize += AS_PTR_SIZE;
  9415. }
  9416. #endif
  9417. if( descr->funcType == asFUNC_IMPORTED )
  9418. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  9419. // TODO: Maybe we need two different byte codes
  9420. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  9421. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  9422. else if( descr->funcType == asFUNC_SCRIPT )
  9423. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  9424. else if( descr->funcType == asFUNC_SYSTEM )
  9425. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  9426. else if( descr->funcType == asFUNC_FUNCDEF )
  9427. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  9428. }
  9429. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  9430. {
  9431. int returnOffset = 0;
  9432. #ifndef AS_OLD
  9433. if( descr->DoesReturnOnStack() )
  9434. {
  9435. asASSERT( useVariable );
  9436. // The variable was allocated before the function was called
  9437. returnOffset = varOffset;
  9438. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9439. // The variable was initialized by the function, so we need to mark it as initialized here
  9440. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  9441. }
  9442. else
  9443. #endif
  9444. {
  9445. if( useVariable )
  9446. {
  9447. // Use the given variable
  9448. returnOffset = varOffset;
  9449. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  9450. }
  9451. else
  9452. {
  9453. // Allocate a temporary variable for the returned object
  9454. // The returned object will actually be allocated on the heap, so
  9455. // we must force the allocation of the variable to do the same
  9456. returnOffset = AllocateVariable(descr->returnType, true, true);
  9457. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  9458. }
  9459. // Move the pointer from the object register to the temporary variable
  9460. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9461. }
  9462. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  9463. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  9464. // Clean up arguments
  9465. if( args )
  9466. AfterFunctionCall(funcId, *args, ctx, false);
  9467. ProcessDeferredParams(ctx);
  9468. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9469. }
  9470. else if( descr->returnType.IsReference() )
  9471. {
  9472. asASSERT(useVariable == false);
  9473. // We cannot clean up the arguments yet, because the
  9474. // reference might be pointing to one of them.
  9475. if( args )
  9476. AfterFunctionCall(funcId, *args, ctx, true);
  9477. // Do not process the output parameters yet, because it
  9478. // might invalidate the returned reference
  9479. // If the context holds a variable that needs cleanup
  9480. // store it as a deferred parameter so it will be cleaned up
  9481. // afterwards.
  9482. if( ctx->type.isTemporary )
  9483. {
  9484. asSDeferredParam defer;
  9485. defer.argNode = 0;
  9486. defer.argType = ctx->type;
  9487. defer.argInOutFlags = asTM_INOUTREF;
  9488. defer.origExpr = 0;
  9489. ctx->deferredParams.PushLast(defer);
  9490. }
  9491. ctx->type.Set(descr->returnType);
  9492. if( !descr->returnType.IsPrimitive() )
  9493. {
  9494. ctx->bc.Instr(asBC_PshRPtr);
  9495. if( descr->returnType.IsObject() &&
  9496. !descr->returnType.IsObjectHandle() )
  9497. {
  9498. // We are getting the pointer to the object
  9499. // not a pointer to a object variable
  9500. ctx->type.dataType.MakeReference(false);
  9501. }
  9502. }
  9503. // A returned reference can be used as lvalue
  9504. ctx->type.isLValue = true;
  9505. }
  9506. else
  9507. {
  9508. asASSERT(useVariable == false);
  9509. if( descr->returnType.GetSizeInMemoryBytes() )
  9510. {
  9511. // Allocate a temporary variable to hold the value, but make sure
  9512. // the temporary variable isn't used in any of the deferred arguments
  9513. int l = reservedVariables.GetLength();
  9514. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  9515. {
  9516. asSExprContext *expr = (*args)[n]->origExpr;
  9517. if( expr )
  9518. expr->bc.GetVarsUsed(reservedVariables);
  9519. }
  9520. int offset = AllocateVariable(descr->returnType, true);
  9521. reservedVariables.SetLength(l);
  9522. ctx->type.SetVariable(descr->returnType, offset, true);
  9523. // Move the value from the return register to the variable
  9524. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  9525. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  9526. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  9527. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  9528. }
  9529. else
  9530. ctx->type.Set(descr->returnType);
  9531. ctx->type.isLValue = false;
  9532. // Clean up arguments
  9533. if( args )
  9534. AfterFunctionCall(funcId, *args, ctx, false);
  9535. ProcessDeferredParams(ctx);
  9536. }
  9537. }
  9538. // This only merges the bytecode, but doesn't modify the type of the final context
  9539. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  9540. {
  9541. before->bc.AddCode(&after->bc);
  9542. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  9543. {
  9544. before->deferredParams.PushLast(after->deferredParams[n]);
  9545. after->deferredParams[n].origExpr = 0;
  9546. }
  9547. after->deferredParams.SetLength(0);
  9548. }
  9549. // This merges both bytecode and the type of the final context
  9550. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  9551. {
  9552. MergeExprBytecode(before, after);
  9553. before->type = after->type;
  9554. before->property_get = after->property_get;
  9555. before->property_set = after->property_set;
  9556. before->property_const = after->property_const;
  9557. before->property_handle = after->property_handle;
  9558. before->property_ref = after->property_ref;
  9559. before->property_arg = after->property_arg;
  9560. before->exprNode = after->exprNode;
  9561. after->property_arg = 0;
  9562. // Do not copy the origExpr member
  9563. }
  9564. void asCCompiler::FilterConst(asCArray<int> &funcs)
  9565. {
  9566. if( funcs.GetLength() == 0 ) return;
  9567. // This is only done for object methods
  9568. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  9569. if( desc->objectType == 0 ) return;
  9570. // Check if there are any non-const matches
  9571. asUINT n;
  9572. bool foundNonConst = false;
  9573. for( n = 0; n < funcs.GetLength(); n++ )
  9574. {
  9575. desc = builder->GetFunctionDescription(funcs[n]);
  9576. if( !desc->isReadOnly )
  9577. {
  9578. foundNonConst = true;
  9579. break;
  9580. }
  9581. }
  9582. if( foundNonConst )
  9583. {
  9584. // Remove all const methods
  9585. for( n = 0; n < funcs.GetLength(); n++ )
  9586. {
  9587. desc = builder->GetFunctionDescription(funcs[n]);
  9588. if( desc->isReadOnly )
  9589. {
  9590. if( n == funcs.GetLength() - 1 )
  9591. funcs.PopLast();
  9592. else
  9593. funcs[n] = funcs.PopLast();
  9594. n--;
  9595. }
  9596. }
  9597. }
  9598. }
  9599. END_AS_NAMESPACE