as_compiler.cpp 330 KB

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