as_compiler.cpp 517 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2021 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. andreas@angelcode.com
  22. */
  23. //
  24. // as_compiler.cpp
  25. //
  26. // The class that does the actual compilation of the functions
  27. //
  28. #include <math.h> // fmodf() pow()
  29. #include "as_config.h"
  30. #ifndef AS_NO_COMPILER
  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. #include "as_debug.h"
  38. #include "as_context.h" // as_powi()
  39. BEGIN_AS_NAMESPACE
  40. //
  41. // The calling convention rules for script functions:
  42. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  43. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  44. // - The object pointer is always passed as the first argument, position 0
  45. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  46. //
  47. // TODO: I must correct the interpretation of a reference to objects in the compiler.
  48. // A reference should mean that a pointer to the object is on the stack.
  49. // No expression should end up as non-references to objects, as the actual object is
  50. // never put on the stack.
  51. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  52. // Function parameters of called functions can also be non-references, but in that case it means the
  53. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  54. //
  55. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  56. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  57. // is currently stored, i.e. in variable, in register, on stack, etc.
  58. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  59. {
  60. builder = 0;
  61. script = 0;
  62. variables = 0;
  63. isProcessingDeferredParams = false;
  64. isCompilingDefaultArg = false;
  65. noCodeOutput = 0;
  66. }
  67. asCCompiler::~asCCompiler()
  68. {
  69. while( variables )
  70. {
  71. asCVariableScope *var = variables;
  72. variables = variables->parent;
  73. asDELETE(var,asCVariableScope);
  74. }
  75. // Clean up all the string constants that were allocated. By now the script
  76. // functions that were compiled successfully already holds their own references
  77. for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
  78. engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
  79. usedStringConstants.SetLength(0);
  80. // Clean up the temporary script nodes that were allocated during compilation
  81. for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++)
  82. nodesToFreeUponComplete[n]->Destroy(engine);
  83. }
  84. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  85. {
  86. this->builder = in_builder;
  87. this->engine = in_builder->engine;
  88. this->script = in_script;
  89. this->outFunc = in_outFunc;
  90. hasCompileErrors = false;
  91. m_isConstructor = false;
  92. m_isConstructorCalled = false;
  93. m_classDecl = 0;
  94. m_globalVar = 0;
  95. nextLabel = 0;
  96. breakLabels.SetLength(0);
  97. continueLabels.SetLength(0);
  98. numLambdas = 0;
  99. byteCode.ClearAll();
  100. }
  101. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  102. {
  103. Reset(in_builder, in_script, in_outFunc);
  104. m_classDecl = in_classDecl;
  105. // Insert a JitEntry at the start of the function for JIT compilers
  106. byteCode.InstrPTR(asBC_JitEntry, 0);
  107. // Add a variable scope that might be needed to declare dummy variables
  108. // in case the member initialization refers to undefined symbols.
  109. AddVariableScope();
  110. // Initialize the class members that have no explicit expression first. This will allow the
  111. // base class' constructor to access these members without worry they will be uninitialized.
  112. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  113. CompileMemberInitialization(&byteCode, true);
  114. // If the class is derived from another, then the base class' default constructor must be called
  115. if( outFunc->objectType->derivedFrom )
  116. {
  117. // Make sure the base class really has a default constructor
  118. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  119. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  120. // Call the base class' default constructor
  121. byteCode.InstrSHORT(asBC_PSF, 0);
  122. byteCode.Instr(asBC_RDSPtr);
  123. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  124. }
  125. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  126. // to access the base class members without worry they will be uninitialized
  127. CompileMemberInitialization(&byteCode, false);
  128. byteCode.OptimizeLocally(tempVariableOffsets);
  129. // If there are compile errors, there is no reason to build the final code
  130. if( hasCompileErrors )
  131. return -1;
  132. // Pop the object pointer from the stack
  133. byteCode.Ret(AS_PTR_SIZE);
  134. // Count total variable size
  135. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  136. outFunc->scriptData->variableSpace = varSize;
  137. FinalizeFunction();
  138. #ifdef AS_DEBUG
  139. // DEBUG: output byte code
  140. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  141. #endif
  142. return 0;
  143. }
  144. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  145. {
  146. Reset(in_builder, in_script, in_outFunc);
  147. // Insert a JitEntry at the start of the function for JIT compilers
  148. byteCode.InstrPTR(asBC_JitEntry, 0);
  149. // Find the corresponding constructor
  150. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  151. int constructor = 0;
  152. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  153. {
  154. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  155. {
  156. constructor = dt.GetBehaviour()->constructors[n];
  157. break;
  158. }
  159. }
  160. // Allocate the class and instantiate it with the constructor
  161. int varOffset = AllocateVariable(dt, true);
  162. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  163. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  164. // Copy all arguments to the top of the stack
  165. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  166. int offset = (int)outFunc->GetSpaceNeededForArguments();
  167. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  168. {
  169. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  170. outFunc->parameterTypes[a].IsReference() )
  171. {
  172. offset -= AS_PTR_SIZE;
  173. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  174. }
  175. else
  176. {
  177. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  178. {
  179. offset -= 2;
  180. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  181. }
  182. else
  183. {
  184. offset -= 1;
  185. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  186. }
  187. }
  188. }
  189. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  190. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  191. // Return a handle to the newly created object
  192. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  193. byteCode.Ret(argDwords);
  194. FinalizeFunction();
  195. // Tell the virtual machine not to clean up parameters on exception
  196. outFunc->dontCleanUpOnException = true;
  197. /*
  198. #ifdef AS_DEBUG
  199. // DEBUG: output byte code
  200. asCString args;
  201. args.Format("%d", outFunc->parameterTypes.GetLength());
  202. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  203. #endif
  204. */
  205. return 0;
  206. }
  207. void asCCompiler::FinalizeFunction()
  208. {
  209. TimeIt("asCCompiler::FinalizeFunction");
  210. asASSERT( outFunc->scriptData );
  211. asUINT n;
  212. // Finalize the bytecode
  213. byteCode.Finalize(tempVariableOffsets);
  214. // extract the try/catch info before object variable info, as
  215. // some variable info is not needed if there are no try/catch blocks
  216. byteCode.ExtractTryCatchInfo(outFunc);
  217. byteCode.ExtractObjectVariableInfo(outFunc);
  218. // Compile the list of object variables for the exception handler
  219. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  220. for( n = 0; n < variableAllocations.GetLength(); n++ )
  221. {
  222. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  223. {
  224. if( variableIsOnHeap[n] )
  225. {
  226. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  227. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  228. }
  229. }
  230. }
  231. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  232. for( n = 0; n < variableAllocations.GetLength(); n++ )
  233. {
  234. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  235. {
  236. if( !variableIsOnHeap[n] )
  237. {
  238. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  239. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  240. }
  241. }
  242. }
  243. // Copy byte code to the function
  244. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  245. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  246. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  247. outFunc->AddReferences();
  248. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  249. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  250. // Extract the script section indexes too if there are any entries that are different from the function's script section
  251. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  252. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  253. {
  254. if( byteCode.sectionIdxs[n] != lastIdx )
  255. {
  256. lastIdx = byteCode.sectionIdxs[n];
  257. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  258. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  259. }
  260. }
  261. }
  262. // internal
  263. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  264. {
  265. int stackPos = 0;
  266. if( outFunc->objectType )
  267. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  268. // Add the first variable scope, which the parameters and
  269. // variables declared in the outermost statement block is
  270. // part of.
  271. AddVariableScope();
  272. bool isDestructor = false;
  273. asCDataType returnType;
  274. // Examine return type
  275. returnType = outFunc->returnType;
  276. // Check if this is a constructor or destructor
  277. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  278. {
  279. if( outFunc->name[0] == '~' )
  280. isDestructor = true;
  281. else if( outFunc->objectType->name == outFunc->name )
  282. m_isConstructor = true;
  283. }
  284. // Is the return type allowed?
  285. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  286. !returnType.CanBeInstantiated() &&
  287. !returnType.IsReference() &&
  288. !returnType.IsObjectHandle() )
  289. {
  290. // TODO: Hasn't this been validated by the builder already?
  291. asCString str;
  292. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  293. Error(str, func);
  294. }
  295. // If the return type is a value type returned by value the address of the
  296. // location where the value will be stored is pushed on the stack before
  297. // the arguments
  298. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  299. stackPos -= AS_PTR_SIZE;
  300. asCVariableScope vs(0);
  301. // Declare parameters
  302. asUINT n;
  303. for( n = 0; n < parameterNames.GetLength(); n++ )
  304. {
  305. // Get the parameter type
  306. asCDataType &type = outFunc->parameterTypes[n];
  307. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  308. // Is the data type allowed?
  309. // TODO: Hasn't this been validated by the builder already?
  310. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  311. (!type.IsReference() && !type.CanBeInstantiated()) )
  312. {
  313. asCString parm = type.Format(outFunc->nameSpace);
  314. if( inoutFlag == asTM_INREF )
  315. parm += "in";
  316. else if( inoutFlag == asTM_OUTREF )
  317. parm += "out";
  318. asCString str;
  319. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  320. Error(str, func);
  321. }
  322. // If the parameter has a name then declare it as variable
  323. if( parameterNames[n] != "" )
  324. {
  325. asCString &name = parameterNames[n];
  326. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  327. {
  328. // TODO: It might be an out-of-memory too
  329. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  330. }
  331. // Add marker for variable declaration
  332. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  333. outFunc->AddVariable(name, type, stackPos);
  334. }
  335. else
  336. vs.DeclareVariable("", type, stackPos, true);
  337. // Move to next parameter
  338. stackPos -= type.GetSizeOnStackDWords();
  339. }
  340. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  341. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  342. variables->DeclareVariable("return", returnType, stackPos, true);
  343. return stackPos;
  344. }
  345. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  346. {
  347. asASSERT( m_classDecl );
  348. // Initialize each member in the order they were declared
  349. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  350. {
  351. asCObjectProperty *prop = outFunc->objectType->properties[n];
  352. // Check if the property has an initialization expression
  353. asCParser parser(builder);
  354. asCScriptNode *declNode = 0;
  355. asCScriptNode *initNode = 0;
  356. asCScriptCode *initScript = 0;
  357. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  358. {
  359. if( m_classDecl->propInits[m].name == prop->name )
  360. {
  361. declNode = m_classDecl->propInits[m].declNode;
  362. initNode = m_classDecl->propInits[m].initNode;
  363. initScript = m_classDecl->propInits[m].file;
  364. break;
  365. }
  366. }
  367. // If declNode is null, the property was inherited in which case
  368. // it was already initialized by the base class' constructor
  369. if( declNode )
  370. {
  371. if( initNode )
  372. {
  373. if( onlyDefaults )
  374. continue;
  375. #ifdef AS_NO_MEMBER_INIT
  376. // Give an error as the initialization in the declaration has been disabled
  377. asCScriptCode *origScript = script;
  378. script = initScript;
  379. Error("Initialization of members in declaration is not supported", initNode);
  380. script = origScript;
  381. // Clear the initialization node
  382. initNode = 0;
  383. initScript = script;
  384. #else
  385. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  386. int r = parser.ParseVarInit(initScript, initNode);
  387. if( r < 0 )
  388. continue;
  389. initNode = parser.GetScriptNode();
  390. #endif
  391. }
  392. else
  393. {
  394. if( !onlyDefaults )
  395. continue;
  396. }
  397. #ifdef AS_NO_MEMBER_INIT
  398. // The initialization will be done in the asCScriptObject constructor, so
  399. // here we should just validate that the member has a default constructor
  400. if( prop->type.IsObject() &&
  401. !prop->type.IsObjectHandle() &&
  402. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  403. prop->type.GetBehaviour()->factory == 0) ||
  404. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  405. prop->type.GetBehaviour()->construct == 0 &&
  406. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  407. {
  408. // Class has no default factory/constructor.
  409. asCString str;
  410. // TODO: funcdef: asCDataType should have a GetTypeName()
  411. if( prop->type.GetFuncDef() )
  412. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  413. else
  414. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  415. Error(str, declNode);
  416. }
  417. #else
  418. // Temporarily set the script that is being compiled to where the member initialization is declared.
  419. // The script can be different when including mixin classes from a different script section
  420. asCScriptCode *origScript = script;
  421. script = initScript;
  422. // Add a line instruction with the position of the declaration
  423. LineInstr(bc, declNode->tokenPos);
  424. // Compile the initialization
  425. asQWORD constantValue;
  426. asCByteCode bcInit(engine);
  427. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  428. bcInit.OptimizeLocally(tempVariableOffsets);
  429. bc->AddCode(&bcInit);
  430. script = origScript;
  431. #endif
  432. }
  433. }
  434. }
  435. // Entry
  436. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  437. {
  438. TimeIt("asCCompiler::CompileFunction");
  439. Reset(in_builder, in_script, in_outFunc);
  440. int buildErrors = builder->numErrors;
  441. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  442. //--------------------------------------------
  443. // Compile the statement block
  444. if( m_isConstructor )
  445. m_classDecl = in_classDecl;
  446. // We need to parse the statement block now
  447. asCScriptNode *blockBegin;
  448. // If the function signature was implicit, e.g. virtual property accessor or
  449. // lambda function, then the received node already is the statement block
  450. if( in_func->nodeType != snStatementBlock )
  451. blockBegin = in_func->lastChild;
  452. else
  453. blockBegin = in_func;
  454. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  455. // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated
  456. asCParser parser(builder);
  457. int r = parser.ParseStatementBlock(script, blockBegin);
  458. if( r < 0 ) return -1;
  459. asCScriptNode *block = parser.GetScriptNode();
  460. // Reserve a label for the cleanup code
  461. nextLabel++;
  462. bool hasReturn;
  463. asCByteCode bc(engine);
  464. LineInstr(&bc, blockBegin->tokenPos);
  465. CompileStatementBlock(block, false, &hasReturn, &bc);
  466. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  467. // Make sure there is a return in all paths (if not return type is void)
  468. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  469. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  470. {
  471. if( hasReturn == false )
  472. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  473. }
  474. //------------------------------------------------
  475. // Concatenate the bytecode
  476. // Insert a JitEntry at the start of the function for JIT compilers
  477. byteCode.InstrPTR(asBC_JitEntry, 0);
  478. if( outFunc->objectType )
  479. {
  480. if( m_isConstructor )
  481. {
  482. if( outFunc->objectType->derivedFrom )
  483. {
  484. // Call the base class' default constructor unless called manually in the code
  485. if( !m_isConstructorCalled )
  486. {
  487. if( outFunc->objectType->derivedFrom->beh.construct )
  488. {
  489. // Initialize members without explicit expression first
  490. CompileMemberInitialization(&byteCode, true);
  491. // Call base class' constructor
  492. asCByteCode tmpBC(engine);
  493. tmpBC.InstrSHORT(asBC_PSF, 0);
  494. tmpBC.Instr(asBC_RDSPtr);
  495. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  496. tmpBC.OptimizeLocally(tempVariableOffsets);
  497. byteCode.AddCode(&tmpBC);
  498. // Add the initialization of the members with explicit expressions
  499. CompileMemberInitialization(&byteCode, false);
  500. }
  501. else
  502. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  503. }
  504. else
  505. {
  506. // Only initialize members that don't have an explicit expression
  507. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  508. CompileMemberInitialization(&byteCode, true);
  509. }
  510. }
  511. else
  512. {
  513. // Add the initialization of the members
  514. CompileMemberInitialization(&byteCode, true);
  515. CompileMemberInitialization(&byteCode, false);
  516. }
  517. }
  518. }
  519. // Add the code for the statement block
  520. byteCode.AddCode(&bc);
  521. // Count total variable size
  522. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  523. outFunc->scriptData->variableSpace = varSize;
  524. // Deallocate all local variables
  525. int n;
  526. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  527. {
  528. sVariable *v = variables->variables[n];
  529. if( v->stackOffset > 0 )
  530. {
  531. // Call variables destructors
  532. if( v->name != "return" && v->name != "return address" )
  533. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  534. DeallocateVariable(v->stackOffset);
  535. }
  536. }
  537. // This is the label that return statements jump to
  538. // in order to exit the function
  539. byteCode.Label(0);
  540. // Call destructors for function parameters
  541. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  542. {
  543. sVariable *v = variables->variables[n];
  544. if( v->stackOffset <= 0 )
  545. {
  546. // Call variable destructors here, for variables not yet destroyed
  547. if( v->name != "return" && v->name != "return address" )
  548. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  549. }
  550. // Do not deallocate parameters
  551. }
  552. // Check if the number of labels in the functions isn't too many to be handled
  553. if( nextLabel >= (1<<15) )
  554. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  555. // If there are compile errors, there is no reason to build the final code
  556. if( hasCompileErrors || builder->numErrors != buildErrors )
  557. return -1;
  558. // At this point there should be no variables allocated
  559. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  560. // Remove the variable scope
  561. RemoveVariableScope();
  562. byteCode.Ret(-stackPos);
  563. FinalizeFunction();
  564. #ifdef AS_DEBUG
  565. // DEBUG: output byte code
  566. if( outFunc->objectType )
  567. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  568. else
  569. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  570. #endif
  571. return 0;
  572. }
  573. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  574. {
  575. if( !type.IsObject() )
  576. return 0;
  577. // CallCopyConstructor should not be called for object handles.
  578. asASSERT( !type.IsObjectHandle() );
  579. asCArray<asCExprContext*> args;
  580. args.PushLast(arg);
  581. // The reference parameter must be pushed on the stack
  582. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  583. // Since we're calling the copy constructor, we have to trust the function to not do
  584. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  585. // copies of the argument in order to guarantee safety.
  586. if( type.GetTypeInfo()->flags & asOBJ_REF )
  587. {
  588. asCExprContext ctx(engine);
  589. int func = 0;
  590. asSTypeBehaviour *beh = type.GetBehaviour();
  591. if( beh ) func = beh->copyfactory;
  592. if( func > 0 )
  593. {
  594. if( !isGlobalVar )
  595. {
  596. // Call factory and store the handle in the given variable
  597. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  598. // Pop the reference left by the function call
  599. ctx.bc.Instr(asBC_PopPtr);
  600. }
  601. else
  602. {
  603. // Call factory
  604. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  605. // Store the returned handle in the global variable
  606. ctx.bc.Instr(asBC_RDSPtr);
  607. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  608. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  609. ctx.bc.Instr(asBC_PopPtr);
  610. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  611. }
  612. bc->AddCode(&ctx.bc);
  613. return 0;
  614. }
  615. }
  616. else
  617. {
  618. asSTypeBehaviour *beh = type.GetBehaviour();
  619. int func = beh ? beh->copyconstruct : 0;
  620. if( func > 0 )
  621. {
  622. // Push the address where the object will be stored on the stack, before the argument
  623. // TODO: When the context is serializable this probably has to be changed, since this
  624. // pointer can remain on the stack while the context is suspended. There is no
  625. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  626. asCByteCode tmp(engine);
  627. if( isGlobalVar )
  628. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  629. else if( isObjectOnHeap )
  630. tmp.InstrSHORT(asBC_PSF, (short)offset);
  631. tmp.AddCode(bc);
  632. bc->AddCode(&tmp);
  633. // When the object is allocated on the stack the object pointer
  634. // must be pushed on the stack after the arguments
  635. if( !isObjectOnHeap )
  636. {
  637. asASSERT( !isGlobalVar );
  638. bc->InstrSHORT(asBC_PSF, (short)offset);
  639. if( derefDest )
  640. {
  641. // The variable is a reference to the real location, so we need to dereference it
  642. bc->Instr(asBC_RDSPtr);
  643. }
  644. }
  645. asCExprContext ctx(engine);
  646. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  647. bc->AddCode(&ctx.bc);
  648. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  649. // Mark the object as initialized
  650. if( !isObjectOnHeap )
  651. bc->ObjInfo(offset, asOBJ_INIT);
  652. return 0;
  653. }
  654. }
  655. // Class has no copy constructor/factory.
  656. asCString str;
  657. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  658. Error(str, node);
  659. return -1;
  660. }
  661. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  662. {
  663. if( !type.IsObject() || type.IsObjectHandle() )
  664. return 0;
  665. if( type.GetTypeInfo()->flags & asOBJ_REF )
  666. {
  667. asCExprContext ctx(engine);
  668. ctx.exprNode = node;
  669. int func = 0;
  670. asSTypeBehaviour *beh = type.GetBehaviour();
  671. if( beh )
  672. {
  673. func = beh->factory;
  674. // If no trivial default factory is found, look for a factory where all params have default args
  675. if( func == 0 )
  676. {
  677. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  678. {
  679. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  680. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  681. f->defaultArgs[0] != 0 )
  682. {
  683. func = beh->factories[n];
  684. break;
  685. }
  686. }
  687. }
  688. }
  689. if( func > 0 )
  690. {
  691. asCArray<asCExprContext *> args;
  692. asCScriptFunction *f = engine->scriptFunctions[func];
  693. if( f->parameterTypes.GetLength() )
  694. {
  695. // Add the default values for arguments not explicitly supplied
  696. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  697. PrepareFunctionCall(func, &ctx.bc, args);
  698. MoveArgsToStack(func, &ctx.bc, args, false);
  699. }
  700. if( isVarGlobOrMem == 0 )
  701. {
  702. // Call factory and store the handle in the given variable
  703. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  704. // Pop the reference left by the function call
  705. ctx.bc.Instr(asBC_PopPtr);
  706. }
  707. else
  708. {
  709. // Call factory
  710. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  711. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  712. // instead of first storing it in a local variable and then copying it to the
  713. // destination.
  714. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  715. {
  716. // Only dereference the variable if not a scoped type
  717. ctx.bc.Instr(asBC_RDSPtr);
  718. }
  719. if( isVarGlobOrMem == 1 )
  720. {
  721. // Store the returned handle in the global variable
  722. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  723. }
  724. else
  725. {
  726. // Store the returned handle in the class member
  727. ctx.bc.InstrSHORT(asBC_PSF, 0);
  728. ctx.bc.Instr(asBC_RDSPtr);
  729. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  730. }
  731. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  732. {
  733. // For scoped typed we must move the reference from the local
  734. // variable rather than copy it as there is no AddRef behaviour
  735. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  736. // Clear the local variable so the reference isn't released
  737. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  738. }
  739. else
  740. {
  741. if( type.IsFuncdef() )
  742. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  743. else
  744. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  745. }
  746. ctx.bc.Instr(asBC_PopPtr);
  747. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  748. }
  749. bc->AddCode(&ctx.bc);
  750. // Cleanup
  751. for( asUINT n = 0; n < args.GetLength(); n++ )
  752. if( args[n] )
  753. {
  754. asDELETE(args[n], asCExprContext);
  755. }
  756. return 0;
  757. }
  758. }
  759. else
  760. {
  761. asCExprContext ctx(engine);
  762. ctx.exprNode = node;
  763. asSTypeBehaviour *beh = type.GetBehaviour();
  764. int func = 0;
  765. if( beh )
  766. {
  767. func = beh->construct;
  768. // If no trivial default constructor is found, look for a constructor where all params have default args
  769. if( func == 0 )
  770. {
  771. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  772. {
  773. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  774. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  775. f->defaultArgs[0] != 0 )
  776. {
  777. func = beh->constructors[n];
  778. break;
  779. }
  780. }
  781. }
  782. }
  783. // Allocate and initialize with the default constructor
  784. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  785. {
  786. asCArray<asCExprContext *> args;
  787. asCScriptFunction *f = engine->scriptFunctions[func];
  788. if( f && f->parameterTypes.GetLength() )
  789. {
  790. // Add the default values for arguments not explicitly supplied
  791. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  792. PrepareFunctionCall(func, &ctx.bc, args);
  793. MoveArgsToStack(func, &ctx.bc, args, false);
  794. }
  795. if( !isObjectOnHeap )
  796. {
  797. if( isVarGlobOrMem == 0 )
  798. {
  799. // There is nothing to do if there is no function,
  800. // as the memory is already allocated on the stack
  801. if( func )
  802. {
  803. // Call the constructor as a normal function
  804. bc->InstrSHORT(asBC_PSF, (short)offset);
  805. if( derefDest )
  806. bc->Instr(asBC_RDSPtr);
  807. asCExprContext ctxCall(engine);
  808. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  809. bc->AddCode(&ctxCall.bc);
  810. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  811. // Mark the object as initialized
  812. bc->ObjInfo(offset, asOBJ_INIT);
  813. }
  814. }
  815. else if( isVarGlobOrMem == 2 )
  816. {
  817. // Only POD types can be allocated inline in script classes
  818. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  819. if( func )
  820. {
  821. // Call the constructor as a normal function
  822. bc->InstrSHORT(asBC_PSF, 0);
  823. bc->Instr(asBC_RDSPtr);
  824. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  825. asCExprContext ctxCall(engine);
  826. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  827. bc->AddCode(&ctxCall.bc);
  828. }
  829. }
  830. else
  831. {
  832. asASSERT( false );
  833. }
  834. }
  835. else
  836. {
  837. if( isVarGlobOrMem == 0 )
  838. bc->InstrSHORT(asBC_PSF, (short)offset);
  839. else if( isVarGlobOrMem == 1 )
  840. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  841. else
  842. {
  843. bc->InstrSHORT(asBC_PSF, 0);
  844. bc->Instr(asBC_RDSPtr);
  845. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  846. }
  847. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  848. {
  849. asCScriptFunction *descr = engine->scriptFunctions[func];
  850. asASSERT( descr->funcType == asFUNC_SCRIPT );
  851. // Find the id of the real constructor and not the generated stub
  852. asUINT id = 0;
  853. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  854. while( funcBc )
  855. {
  856. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  857. {
  858. id = asBC_INTARG(funcBc);
  859. break;
  860. }
  861. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  862. }
  863. asASSERT( id );
  864. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  865. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  866. }
  867. else
  868. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  869. }
  870. // Cleanup
  871. for( asUINT n = 0; n < args.GetLength(); n++ )
  872. if( args[n] )
  873. {
  874. asDELETE(args[n], asCExprContext);
  875. }
  876. return 0;
  877. }
  878. }
  879. // Class has no default factory/constructor.
  880. asCString str;
  881. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  882. Error(str, node);
  883. return -1;
  884. }
  885. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  886. {
  887. if( !type.IsReference() )
  888. {
  889. // Call destructor for the data type
  890. if( type.IsObject() || type.IsFuncdef() )
  891. {
  892. // The null pointer doesn't need to be destroyed
  893. if( type.IsNullHandle() )
  894. return;
  895. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  896. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  897. return;
  898. if( isObjectOnHeap || type.IsObjectHandle() )
  899. {
  900. // Free the memory
  901. if (type.IsFuncdef())
  902. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  903. else
  904. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  905. }
  906. else
  907. {
  908. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  909. if( type.GetBehaviour()->destruct )
  910. {
  911. // Call the destructor as a regular function
  912. asCExprContext ctx(engine);
  913. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  914. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  915. ctx.bc.OptimizeLocally(tempVariableOffsets);
  916. bc->AddCode(&ctx.bc);
  917. }
  918. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  919. // Mark the object as destroyed
  920. bc->ObjInfo(offset, asOBJ_UNINIT);
  921. }
  922. }
  923. }
  924. }
  925. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  926. {
  927. int r, c;
  928. script->ConvertPosToRowCol(pos, &r, &c);
  929. bc->Line(r, c, script->idx);
  930. }
  931. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  932. {
  933. *hasReturn = false;
  934. bool isFinished = false;
  935. bool hasUnreachableCode = false;
  936. bool hasReturnBefore = false;
  937. if( ownVariableScope )
  938. {
  939. bc->Block(true);
  940. AddVariableScope();
  941. }
  942. asCScriptNode *node = block->firstChild;
  943. while( node )
  944. {
  945. #ifdef AS_DEBUG
  946. // Keep the current line in a variable so it will be easier
  947. // to determine where in a script an assert is occurring.
  948. int currentLine = 0;
  949. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  950. #endif
  951. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  952. {
  953. // Empty statements don't count
  954. if( node->nodeType != snExpressionStatement || node->firstChild )
  955. {
  956. hasUnreachableCode = true;
  957. Warning(TXT_UNREACHABLE_CODE, node);
  958. }
  959. if( *hasReturn )
  960. hasReturnBefore = true;
  961. }
  962. if( node->nodeType == snBreak || node->nodeType == snContinue )
  963. isFinished = true;
  964. asCByteCode statement(engine);
  965. if( node->nodeType == snDeclaration )
  966. CompileDeclaration(node, &statement);
  967. else
  968. CompileStatement(node, hasReturn, &statement);
  969. // Ignore missing returns in unreachable code paths
  970. if( !(*hasReturn) && hasReturnBefore )
  971. *hasReturn = true;
  972. LineInstr(bc, node->tokenPos);
  973. bc->AddCode(&statement);
  974. if( !hasCompileErrors )
  975. {
  976. asASSERT( tempVariables.GetLength() == 0 );
  977. asASSERT( reservedVariables.GetLength() == 0 );
  978. }
  979. node = node->next;
  980. }
  981. if( ownVariableScope )
  982. {
  983. // Deallocate variables in this block, in reverse order
  984. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  985. {
  986. sVariable *v = variables->variables[n];
  987. // Call variable destructors here, for variables not yet destroyed
  988. // If the block is terminated with a break, continue, or
  989. // return the variables are already destroyed
  990. if( !isFinished && !*hasReturn )
  991. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  992. // Don't deallocate function parameters
  993. if( v->stackOffset > 0 )
  994. DeallocateVariable(v->stackOffset);
  995. }
  996. RemoveVariableScope();
  997. bc->Block(false);
  998. }
  999. }
  1000. // Entry
  1001. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  1002. {
  1003. Reset(in_builder, in_script, in_outFunc);
  1004. m_globalVar = in_gvar;
  1005. // Add a variable scope (even though variables can't be declared)
  1006. AddVariableScope();
  1007. in_gvar->isPureConstant = false;
  1008. // Parse the initialization nodes
  1009. asCParser parser(builder);
  1010. if (in_node)
  1011. {
  1012. int r = parser.ParseVarInit(in_script, in_node);
  1013. if (r < 0)
  1014. return r;
  1015. in_node = parser.GetScriptNode();
  1016. }
  1017. asCExprContext compiledCtx(engine);
  1018. bool preCompiled = false;
  1019. if (in_gvar->datatype.IsAuto())
  1020. {
  1021. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1022. if (!preCompiled)
  1023. {
  1024. // If it wasn't possible to determine the type from the expression then there
  1025. // is no need to continue with the initialization. The error was already reported
  1026. // in CompileAutoType.
  1027. return -1;
  1028. }
  1029. }
  1030. if( in_gvar->property == 0 )
  1031. {
  1032. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1033. in_gvar->index = in_gvar->property->id;
  1034. }
  1035. // Compile the expression
  1036. asCExprContext ctx(engine);
  1037. asQWORD constantValue = 0;
  1038. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1039. {
  1040. // Should the variable be marked as pure constant?
  1041. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1042. {
  1043. in_gvar->isPureConstant = true;
  1044. in_gvar->constantValue = constantValue;
  1045. }
  1046. }
  1047. // Concatenate the bytecode
  1048. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1049. // Add information on the line number for the global variable
  1050. size_t pos = 0;
  1051. if( in_gvar->declaredAtNode )
  1052. pos = in_gvar->declaredAtNode->tokenPos;
  1053. else if( in_gvar->initializationNode )
  1054. pos = in_gvar->initializationNode->tokenPos;
  1055. LineInstr(&byteCode, pos);
  1056. // Reserve space for all local variables
  1057. outFunc->scriptData->variableSpace = varSize;
  1058. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1059. byteCode.AddCode(&ctx.bc);
  1060. // Deallocate variables in this block, in reverse order
  1061. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1062. {
  1063. sVariable *v = variables->variables[n];
  1064. // Call variable destructors here, for variables not yet destroyed
  1065. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1066. DeallocateVariable(v->stackOffset);
  1067. }
  1068. if( hasCompileErrors ) return -1;
  1069. // At this point there should be no variables allocated
  1070. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1071. // Remove the variable scope again
  1072. RemoveVariableScope();
  1073. byteCode.Ret(0);
  1074. FinalizeFunction();
  1075. #ifdef AS_DEBUG
  1076. // DEBUG: output byte code
  1077. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1078. #endif
  1079. return 0;
  1080. }
  1081. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1082. {
  1083. // Don't do anything if this is not a deferred global function
  1084. if( !ctx->IsGlobalFunc() )
  1085. return;
  1086. // Determine the namespace
  1087. asSNameSpace *ns = 0;
  1088. asCString name = "";
  1089. int pos = ctx->methodName.FindLast("::");
  1090. if( pos >= 0 )
  1091. {
  1092. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1093. // Cut off the ::
  1094. if( nsName.GetLength() > 2 )
  1095. nsName.SetLength(nsName.GetLength()-2);
  1096. ns = DetermineNameSpace(nsName);
  1097. name = ctx->methodName.SubString(pos+2);
  1098. }
  1099. else
  1100. {
  1101. DetermineNameSpace("");
  1102. name = ctx->methodName;
  1103. }
  1104. asCArray<int> funcs;
  1105. if( ns )
  1106. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1107. // CompileVariableAccess should guarantee that at least one function is exists
  1108. asASSERT( funcs.GetLength() > 0 );
  1109. if( funcs.GetLength() > 1 )
  1110. {
  1111. asCString str;
  1112. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1113. Error(str, node);
  1114. // Fall through so the compiler can continue as if only one function was matching
  1115. }
  1116. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1117. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1118. outFunc->IsShared() )
  1119. {
  1120. asCString msg;
  1121. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1122. Error(msg, node);
  1123. // Fall through so the compiler can continue anyway
  1124. }
  1125. // Push the function pointer on the stack
  1126. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1127. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1128. ctx->type.dataType.MakeHandle(true);
  1129. ctx->type.isExplicitHandle = true;
  1130. ctx->methodName = "";
  1131. }
  1132. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1133. {
  1134. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1135. // Use copy constructor if available.
  1136. asCObjectType *ot = CastToObjectType(dt.GetTypeInfo());
  1137. if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory))
  1138. {
  1139. PrepareForAssignment(&dt, arg, node, true);
  1140. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1141. if( r < 0 && tempVariables.Exists(offset) )
  1142. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1143. }
  1144. else
  1145. {
  1146. // TODO: Need to reserve variables, as the default constructor may need
  1147. // to allocate temporary variables to compute default args
  1148. // Allocate and construct the temporary object before whatever is already in the bytecode
  1149. asCByteCode tmpBC(engine);
  1150. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1151. if( r < 0 )
  1152. {
  1153. if( tempVariables.Exists(offset) )
  1154. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1155. return;
  1156. }
  1157. tmpBC.AddCode(bc);
  1158. bc->AddCode(&tmpBC);
  1159. // Assign the evaluated expression to the temporary variable
  1160. PrepareForAssignment(&dt, arg, node, true);
  1161. bc->AddCode(&arg->bc);
  1162. // Call the opAssign method to assign the value to the temporary object
  1163. dt.MakeReference(isObjectOnHeap);
  1164. asCExprValue type;
  1165. type.Set(dt);
  1166. type.isTemporary = true;
  1167. type.stackOffset = (short)offset;
  1168. if( dt.IsObjectHandle() )
  1169. type.isExplicitHandle = true;
  1170. bc->InstrSHORT(asBC_PSF, (short)offset);
  1171. if( derefDestination )
  1172. bc->Instr(asBC_RDSPtr);
  1173. r = PerformAssignment(&type, &arg->type, bc, node);
  1174. if( r < 0 )
  1175. {
  1176. if( tempVariables.Exists(offset) )
  1177. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1178. return;
  1179. }
  1180. // Pop the reference that was pushed on the stack if the result is an object
  1181. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1182. bc->Instr(asBC_PopPtr);
  1183. // If the assignment operator returned an object by value it will
  1184. // be in a temporary variable which we need to destroy now
  1185. if( type.isTemporary && type.stackOffset != (short)offset )
  1186. ReleaseTemporaryVariable(type.stackOffset, bc);
  1187. // Release the original value too in case it is a temporary
  1188. ReleaseTemporaryVariable(arg->type, bc);
  1189. }
  1190. }
  1191. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1192. {
  1193. asCDataType param = *paramType;
  1194. if( paramType->GetTokenType() == ttQuestion )
  1195. {
  1196. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1197. DetermineSingleFunc(ctx, node);
  1198. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1199. param = ctx->type.dataType;
  1200. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1201. // Treat the void expression like a null handle when working with var types
  1202. if( ctx->IsVoidExpression() )
  1203. param = asCDataType::CreateNullHandle();
  1204. // If value assign is disabled for reference types, then make
  1205. // sure to always pass the handle to ? parameters
  1206. if( builder->engine->ep.disallowValueAssignForRefType &&
  1207. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1208. {
  1209. param.MakeHandle(true);
  1210. }
  1211. param.MakeReference(paramType->IsReference());
  1212. param.MakeReadOnly(paramType->IsReadOnly());
  1213. }
  1214. else
  1215. param = *paramType;
  1216. asCDataType dt = param;
  1217. // Need to protect arguments by reference
  1218. if( isFunction && dt.IsReference() )
  1219. {
  1220. // Allocate a temporary variable of the same type as the argument
  1221. dt.MakeReference(false);
  1222. int offset;
  1223. if( refType == asTM_INREF )
  1224. {
  1225. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1226. return -1;
  1227. // Add the type id as hidden arg if the parameter is a ? type
  1228. if( paramType->GetTokenType() == ttQuestion )
  1229. {
  1230. asCByteCode tmpBC(engine);
  1231. // Place the type id on the stack as a hidden parameter
  1232. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1233. // Insert the code before the expression code
  1234. tmpBC.AddCode(&ctx->bc);
  1235. ctx->bc.AddCode(&tmpBC);
  1236. }
  1237. if( dt.IsPrimitive() )
  1238. {
  1239. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1240. // Even if the same variable is passed in another argument as non-const then there is no problem
  1241. IsVariableInitialized(&ctx->type, node);
  1242. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1243. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1244. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1245. ConvertToTempVariable(ctx);
  1246. PushVariableOnStack(ctx, true);
  1247. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1248. }
  1249. else if( ctx->type.dataType.IsNullHandle() )
  1250. {
  1251. // Make sure the argument type can support handles (or is itself a handle)
  1252. // Don't allow null handle to be converted to an object type of ASHANDLE here, that would require more logic to call the constructor (which should be handled in ImplicitConversion)
  1253. if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) )
  1254. {
  1255. asCString str;
  1256. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1257. Error(str, node);
  1258. ctx->type.Set(param);
  1259. return -1;
  1260. }
  1261. // Need to initialize a local temporary variable to
  1262. // represent the null handle when passed as reference
  1263. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1264. ctx->bc.Instr(asBC_PopPtr);
  1265. dt.MakeHandle(true);
  1266. dt.MakeReadOnly(false);
  1267. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1268. // Push the reference to the variable on the stack
  1269. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1270. ctx->type.SetVariable(dt, offset, true);
  1271. ctx->type.isExplicitHandle = true;
  1272. }
  1273. else
  1274. {
  1275. IsVariableInitialized(&ctx->type, node);
  1276. if( !isMakingCopy )
  1277. {
  1278. // For parameters expecting a reference to a handle we need to make sure the argument
  1279. // is really a handle, and not just a reference to the object. Do this check before the
  1280. // implicit conversion so it can be treated correctly.
  1281. if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle())
  1282. {
  1283. // Make a refCopy into a local handle variable
  1284. // Allocate a handle variable
  1285. dt.MakeHandle(true);
  1286. dt.MakeReadOnly(false);
  1287. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1288. // Copy the handle
  1289. Dereference(ctx, true);
  1290. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1291. if (ctx->type.dataType.IsFuncdef())
  1292. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1293. else
  1294. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1295. ctx->bc.Instr(asBC_PopPtr);
  1296. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1297. // Release the original temporary variable
  1298. if( ctx->type.isTemporary )
  1299. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1300. ctx->type.SetVariable(dt, offset, true);
  1301. }
  1302. // Even though the parameter expects a reference, it is only meant to be
  1303. // used as input value and doesn't have to refer to the actual object, so it
  1304. // is OK to do an implicit conversion.
  1305. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1306. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1307. {
  1308. asCString str;
  1309. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1310. Error(str, node);
  1311. ctx->type.Set(param);
  1312. return -1;
  1313. }
  1314. // The compiler must guarantee that the object stays alive during the execution
  1315. // of the function, and it must also guarantee that the value isn't modified by
  1316. // the function.
  1317. // If the argument is a temporary local variable then it is safe to be passed to
  1318. // the function as it is, since the local variable will stay alive, and since it
  1319. // is temporary there is no side effect if the function modifies it.
  1320. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1321. // function, then it is enough that the variable is local to guarantee the lifetime.
  1322. if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) )
  1323. {
  1324. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1325. {
  1326. // Funcdefs only need an extra handle to guarantee the lifetime.
  1327. // If the object is a reference type (except scoped reference types), and the
  1328. // parameter is a const reference, then it is not necessary to make a copy of the
  1329. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1330. // Allocate a handle variable
  1331. dt.MakeHandle(true);
  1332. dt.MakeReadOnly(false);
  1333. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1334. // Copy the handle
  1335. Dereference(ctx, true);
  1336. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1337. if (ctx->type.dataType.IsFuncdef())
  1338. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1339. else
  1340. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1341. ctx->bc.Instr(asBC_PopPtr);
  1342. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1343. // The type should be set to the param type instead of dt to guarantee
  1344. // that the expression keeps the correct type for variable ? args. Otherwise
  1345. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1346. bool isExplicitHandle = ctx->type.isExplicitHandle;
  1347. ctx->type.SetVariable(param, offset, true);
  1348. ctx->type.dataType.MakeHandle(true);
  1349. ctx->type.isExplicitHandle = isExplicitHandle;
  1350. }
  1351. else
  1352. {
  1353. // Make a copy of the object to guarantee that the original isn't modified
  1354. asASSERT(!dt.IsFuncdef());
  1355. // Allocate and initialize a temporary local object
  1356. dt.MakeReadOnly(false);
  1357. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1358. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1359. // Push the object pointer on the stack
  1360. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1361. if( dt.IsObject() && !dt.IsObjectHandle() )
  1362. ctx->bc.Instr(asBC_RDSPtr);
  1363. // Set the resulting type
  1364. ctx->type.Set(dt);
  1365. ctx->type.isTemporary = true;
  1366. ctx->type.stackOffset = short(offset);
  1367. if( dt.IsObjectHandle() )
  1368. ctx->type.isExplicitHandle = true;
  1369. ctx->type.dataType.MakeReference(false);
  1370. if( paramType->IsReadOnly() )
  1371. ctx->type.dataType.MakeReadOnly(true);
  1372. }
  1373. }
  1374. // When calling a function expecting a var arg with a parameter received as reference to handle
  1375. // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
  1376. // not be able to do the correct double dereference to put the reference to the object on the stack.
  1377. if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
  1378. {
  1379. sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
  1380. if (var && var->type.IsReference() && var->type.IsObjectHandle())
  1381. {
  1382. // Copy the handle to local variable
  1383. // Allocate a handle variable
  1384. dt.MakeHandle(true);
  1385. dt.MakeReadOnly(false);
  1386. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1387. // Copy the handle
  1388. Dereference(ctx, true);
  1389. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1390. if (ctx->type.dataType.IsFuncdef())
  1391. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1392. else
  1393. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1394. ctx->bc.Instr(asBC_PopPtr);
  1395. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1396. // The type should be set to the param type instead of dt to guarantee
  1397. // that the expression keeps the correct type for variable ? args. Otherwise
  1398. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1399. ctx->type.SetVariable(param, offset, true);
  1400. }
  1401. }
  1402. }
  1403. else
  1404. {
  1405. // We must guarantee that the address to the value is on the stack
  1406. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1407. !ctx->type.dataType.IsObjectHandle() &&
  1408. ctx->type.dataType.IsReference() )
  1409. Dereference(ctx, true);
  1410. }
  1411. }
  1412. }
  1413. else if( refType == asTM_OUTREF )
  1414. {
  1415. // Add the type id as hidden arg if the parameter is a ? type
  1416. if( paramType->GetTokenType() == ttQuestion )
  1417. {
  1418. asCByteCode tmpBC(engine);
  1419. // Place the type id on the stack as a hidden parameter
  1420. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1421. // Insert the code before the expression code
  1422. tmpBC.AddCode(&ctx->bc);
  1423. ctx->bc.AddCode(&tmpBC);
  1424. }
  1425. // If the expression is marked as clean, then it can be used directly
  1426. // without the need to allocate another temporary value as it is known
  1427. // that the argument has no other value than the default
  1428. if( ctx->isCleanArg )
  1429. {
  1430. // Must be a local variable
  1431. asASSERT( ctx->type.isVariable );
  1432. }
  1433. else
  1434. {
  1435. // Null handles and void expressions must be marked as explicit
  1436. // handles for correct treatement in MoveArgsToStack
  1437. if (dt.IsNullHandle())
  1438. ctx->type.isExplicitHandle = true;
  1439. // Make sure the variable is not used in the expression
  1440. dt.MakeReadOnly(false);
  1441. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1442. if( dt.IsPrimitive() )
  1443. {
  1444. ctx->type.SetVariable(dt, offset, true);
  1445. PushVariableOnStack(ctx, true);
  1446. }
  1447. else
  1448. {
  1449. // Allocate and construct the temporary object
  1450. asCByteCode tmpBC(engine);
  1451. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1452. // Insert the code before the expression code
  1453. tmpBC.AddCode(&ctx->bc);
  1454. ctx->bc.AddCode(&tmpBC);
  1455. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1456. asCExprValue type;
  1457. type.Set(dt);
  1458. type.isTemporary = true;
  1459. type.stackOffset = (short)offset;
  1460. type.isExplicitHandle = ctx->type.isExplicitHandle;
  1461. ctx->type = type;
  1462. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1463. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1464. ctx->bc.Instr(asBC_RDSPtr);
  1465. }
  1466. // After the function returns the temporary variable will
  1467. // be assigned to the expression, if it is a valid lvalue
  1468. }
  1469. }
  1470. else if( refType == asTM_INOUTREF )
  1471. {
  1472. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1473. return -1;
  1474. // Add the type id as hidden arg if the parameter is a ? type
  1475. if( paramType->GetTokenType() == ttQuestion )
  1476. {
  1477. asCByteCode tmpBC(engine);
  1478. // Place the type id on the stack as a hidden parameter
  1479. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1480. // Insert the code before the expression code
  1481. tmpBC.AddCode(&ctx->bc);
  1482. ctx->bc.AddCode(&tmpBC);
  1483. }
  1484. // Literal constants cannot be passed to inout ref arguments
  1485. if( !ctx->type.isVariable &&
  1486. ctx->type.isConstant &&
  1487. !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
  1488. {
  1489. // Unless unsafe references are turned on and the reference is const
  1490. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1491. {
  1492. // Since the parameter is a const & make a copy.
  1493. ConvertToTempVariable(ctx);
  1494. ctx->type.dataType.MakeReadOnly(true);
  1495. }
  1496. else
  1497. {
  1498. Error(TXT_NOT_VALID_REFERENCE, node);
  1499. return -1;
  1500. }
  1501. }
  1502. // Allow anonymous init lists to be converted to the arg type
  1503. if( ctx->IsAnonymousInitList() )
  1504. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true);
  1505. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1506. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1507. // Only objects that support object handles
  1508. // can be guaranteed to be safe. Local variables are
  1509. // already safe, so there is no need to add an extra
  1510. // references
  1511. if( !engine->ep.allowUnsafeReferences &&
  1512. !ctx->type.isVariable &&
  1513. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1514. !ctx->type.dataType.IsObjectHandle() &&
  1515. ((ctx->type.dataType.GetBehaviour()->addref &&
  1516. ctx->type.dataType.GetBehaviour()->release) ||
  1517. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1518. ctx->type.dataType.IsFuncdef()) )
  1519. {
  1520. // Store a handle to the object as local variable
  1521. asCExprContext tmp(engine);
  1522. dt = ctx->type.dataType;
  1523. dt.MakeHandle(true);
  1524. dt.MakeReference(false);
  1525. dt.MakeReadOnly(false);
  1526. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1527. // Copy the handle
  1528. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1529. ctx->bc.Instr(asBC_RDSPtr);
  1530. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1531. if( ctx->type.dataType.IsFuncdef() )
  1532. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1533. else
  1534. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1535. ctx->bc.Instr(asBC_PopPtr);
  1536. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1537. dt.MakeHandle(false);
  1538. dt.MakeReference(true);
  1539. // Release previous temporary variable stored in the context (if any)
  1540. if( ctx->type.isTemporary )
  1541. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1542. ctx->type.SetVariable(dt, offset, true);
  1543. }
  1544. // Make sure the reference to the value is on the stack
  1545. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1546. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1547. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1548. Dereference(ctx, true);
  1549. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1550. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1551. else if( ctx->type.dataType.IsPrimitive() )
  1552. ctx->bc.Instr(asBC_PshRPtr);
  1553. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1554. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1555. }
  1556. }
  1557. else
  1558. {
  1559. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1560. return -1;
  1561. if( dt.IsPrimitive() )
  1562. {
  1563. IsVariableInitialized(&ctx->type, node);
  1564. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1565. // Implicitly convert primitives to the parameter type
  1566. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1567. if( ctx->type.isVariable )
  1568. {
  1569. PushVariableOnStack(ctx, dt.IsReference());
  1570. }
  1571. else if( ctx->type.isConstant )
  1572. {
  1573. ConvertToVariable(ctx);
  1574. PushVariableOnStack(ctx, dt.IsReference());
  1575. }
  1576. }
  1577. else
  1578. {
  1579. IsVariableInitialized(&ctx->type, node);
  1580. // Implicitly convert primitives to the parameter type
  1581. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1582. // Was the conversion successful?
  1583. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1584. {
  1585. asCString str;
  1586. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1587. Error(str, node);
  1588. ctx->type.Set(dt);
  1589. return -1;
  1590. }
  1591. if( dt.IsObjectHandle() )
  1592. ctx->type.isExplicitHandle = true;
  1593. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1594. {
  1595. // Objects passed by value must be placed in temporary variables
  1596. // so that they are guaranteed to not be referenced anywhere else.
  1597. // The object must also be allocated on the heap, as the memory will
  1598. // be deleted by the called function.
  1599. // Handles passed by value must also be placed in a temporary variable
  1600. // to guarantee that the object referred to isn't freed too early.
  1601. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1602. // Don't make temporary copies of handles if it is going to be used
  1603. // for handle assignment anyway, i.e. REFCPY.
  1604. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
  1605. PrepareTemporaryVariable(node, ctx, true);
  1606. }
  1607. }
  1608. }
  1609. // Don't put any pointer on the stack yet
  1610. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1611. {
  1612. // &inout parameter may leave the reference on the stack already
  1613. // references considered safe too, i.e. when the life time is known
  1614. if( refType != asTM_INOUTREF && !ctx->type.isRefSafe )
  1615. {
  1616. asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy );
  1617. if( ctx->type.isVariable || ctx->type.isTemporary )
  1618. {
  1619. ctx->bc.Instr(asBC_PopPtr);
  1620. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1621. ProcessDeferredParams(ctx);
  1622. }
  1623. }
  1624. }
  1625. return 0;
  1626. }
  1627. int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1628. {
  1629. // When a match has been found, compile the final byte code using correct parameter types
  1630. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1631. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1632. // If the function being called is the opAssign or copy constructor for the same type
  1633. // as the argument, then we should avoid making temporary copy of the argument
  1634. bool makingCopy = false;
  1635. if( descr->parameterTypes.GetLength() == 1 &&
  1636. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1637. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1638. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1639. makingCopy = true;
  1640. // Add code for arguments
  1641. asCExprContext e(engine);
  1642. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1643. {
  1644. // Make sure PrepareArgument doesn't use any variable that is already
  1645. // being used by the argument or any of the following argument expressions
  1646. int l = int(reservedVariables.GetLength());
  1647. for( int m = n; m >= 0; m-- )
  1648. args[m]->bc.GetVarsUsed(reservedVariables);
  1649. int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1650. reservedVariables.SetLength(l);
  1651. if (r < 0)
  1652. return r;
  1653. }
  1654. bc->AddCode(&e.bc);
  1655. return 0;
  1656. }
  1657. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1658. {
  1659. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1660. int offset = 0;
  1661. if( addOneToOffset )
  1662. offset += AS_PTR_SIZE;
  1663. // The address of where the return value should be stored is push on top of the arguments
  1664. if( descr->DoesReturnOnStack() )
  1665. offset += AS_PTR_SIZE;
  1666. #ifdef AS_DEBUG
  1667. // If the function being called is the opAssign or copy constructor for the same type
  1668. // as the argument, then we should avoid making temporary copy of the argument
  1669. bool makingCopy = false;
  1670. if( descr->parameterTypes.GetLength() == 1 &&
  1671. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1672. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1673. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1674. makingCopy = true;
  1675. #endif
  1676. // Move the objects that are sent by value to the stack just before the call
  1677. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1678. {
  1679. if( descr->parameterTypes[n].IsReference() )
  1680. {
  1681. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1682. {
  1683. if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe )
  1684. {
  1685. #ifdef AS_DEBUG
  1686. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1687. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1688. #endif
  1689. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1690. {
  1691. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1692. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1693. // as the value allocated on the stack is guaranteed to be safe
  1694. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1695. else
  1696. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1697. }
  1698. }
  1699. if( args[n]->type.dataType.IsObjectHandle() )
  1700. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1701. }
  1702. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1703. {
  1704. // If the argument is already known to be safe, i.e. has a guaranteed lifetime,
  1705. // then the address on the stack is already pointing to the correct object so no
  1706. // need to do anything else
  1707. if (!args[n]->type.isRefSafe)
  1708. {
  1709. if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1710. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1711. !args[n]->type.dataType.IsObjectHandle())
  1712. {
  1713. // Send the object as a reference to the object,
  1714. // and not to the variable holding the object
  1715. if (!IsVariableOnHeap(args[n]->type.stackOffset))
  1716. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1717. // as the value allocated on the stack is guaranteed to be safe
  1718. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1719. else
  1720. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1721. }
  1722. else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1723. args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
  1724. {
  1725. // The object handle is being passed as an object, so dereference it before
  1726. // the call so the reference will be to the object rather than to the handle
  1727. if (engine->ep.disallowValueAssignForRefType)
  1728. {
  1729. // With disallow value assign all ref type objects are always passed by handle
  1730. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1731. }
  1732. else
  1733. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1734. }
  1735. else
  1736. {
  1737. // If the variable is really an argument of @& type, then it is necessary
  1738. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1739. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1740. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1741. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1742. else
  1743. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1744. }
  1745. }
  1746. }
  1747. }
  1748. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1749. {
  1750. asASSERT(!args[n]->type.isRefSafe);
  1751. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1752. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1753. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1754. // The pointer in the variable will be moved to the stack
  1755. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1756. // Deallocate the variable slot so it can be reused, but do not attempt to
  1757. // free the content of the variable since it was moved to the stack for the call
  1758. DeallocateVariable(args[n]->type.stackOffset);
  1759. args[n]->type.isTemporary = false;
  1760. }
  1761. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1762. }
  1763. }
  1764. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1765. {
  1766. asASSERT(node->nodeType == snArgList);
  1767. // Count arguments
  1768. asCScriptNode *arg = node->firstChild;
  1769. int argCount = 0;
  1770. while( arg )
  1771. {
  1772. if( arg->nodeType != snNamedArgument )
  1773. argCount++;
  1774. arg = arg->next;
  1775. }
  1776. // Prepare the arrays
  1777. args.SetLength(argCount);
  1778. int n;
  1779. for( n = 0; n < argCount; n++ )
  1780. args[n] = 0;
  1781. n = argCount-1;
  1782. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1783. bool anyErrors = false, inPositionalArguments = false;
  1784. arg = node->lastChild;
  1785. while( arg )
  1786. {
  1787. asCScriptNode *asgNode = arg, *namedNode = 0;
  1788. if( asgNode->nodeType == snNamedArgument )
  1789. {
  1790. if( inPositionalArguments )
  1791. {
  1792. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1793. return -1;
  1794. }
  1795. asgNode = arg->firstChild->next;
  1796. namedNode = arg->firstChild;
  1797. asASSERT( namedNode->nodeType == snIdentifier );
  1798. }
  1799. else
  1800. inPositionalArguments = true;
  1801. asCExprContext expr(engine);
  1802. int r = CompileAssignment(asgNode, &expr);
  1803. if( r < 0 ) anyErrors = true;
  1804. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1805. if( ctx == 0 )
  1806. {
  1807. // Out of memory
  1808. return -1;
  1809. }
  1810. MergeExprBytecodeAndType(ctx, &expr);
  1811. if( inPositionalArguments )
  1812. {
  1813. args[n] = ctx;
  1814. n--;
  1815. }
  1816. else
  1817. {
  1818. asSNamedArgument namedArg;
  1819. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1820. namedArg.ctx = ctx;
  1821. // Error out when multiple arguments with the same name are passed
  1822. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1823. {
  1824. if( namedArgs[a].name == namedArg.name )
  1825. {
  1826. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1827. anyErrors = true;
  1828. break;
  1829. }
  1830. }
  1831. namedArgs.PushLast(namedArg);
  1832. }
  1833. arg = arg->prev;
  1834. }
  1835. return anyErrors ? -1 : 0;
  1836. }
  1837. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1838. {
  1839. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1840. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1841. return 0;
  1842. // Make sure to use the real function for virtual functions
  1843. if( func->funcType == asFUNC_VIRTUAL )
  1844. {
  1845. asASSERT( objectType );
  1846. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1847. }
  1848. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1849. bool anyErrors = false;
  1850. int prevReservedVars = reservedVariables.GetLength();
  1851. int explicitArgs = (int)args.GetLength();
  1852. for( int p = 0; p < explicitArgs; p++ )
  1853. args[p]->bc.GetVarsUsed(reservedVariables);
  1854. // Make space for all the new arguments
  1855. args.SetLength(func->parameterTypes.GetLength());
  1856. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1857. args[c] = 0;
  1858. // Add the named arguments to the argument list in the right position
  1859. if( namedArgs )
  1860. {
  1861. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1862. {
  1863. asSNamedArgument &named = (*namedArgs)[n];
  1864. named.ctx->bc.GetVarsUsed(reservedVariables);
  1865. // Find the right spot to put it in
  1866. asUINT index = asUINT(-1);
  1867. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1868. {
  1869. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1870. {
  1871. index = j;
  1872. break;
  1873. }
  1874. }
  1875. asASSERT( index < args.GetLength() );
  1876. args[index] = named.ctx;
  1877. named.ctx = 0;
  1878. }
  1879. }
  1880. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1881. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1882. {
  1883. if( args[n] != 0 ) continue;
  1884. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1885. // Parse the default arg string
  1886. asCParser parser(builder);
  1887. asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength());
  1888. int r = parser.ParseExpression(code);
  1889. if( r < 0 )
  1890. {
  1891. asCString msg;
  1892. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1893. Error(msg, node);
  1894. anyErrors = true;
  1895. continue;
  1896. }
  1897. asCScriptNode *arg = parser.GetScriptNode();
  1898. // Temporarily set the script code to the default arg expression
  1899. asCScriptCode *origScript = script;
  1900. script = code;
  1901. // Don't allow the expression to access local variables
  1902. isCompilingDefaultArg = true;
  1903. // Temporarily set the namespace in the output function to the namespace of the called
  1904. // function so that the default arguments are evaluated in the correct namespace
  1905. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1906. outFunc->nameSpace = func->nameSpace;
  1907. asCExprContext expr(engine);
  1908. r = CompileExpression(arg, &expr);
  1909. // Restore the namespace
  1910. outFunc->nameSpace = origNameSpace;
  1911. // Don't allow address of class method
  1912. if( expr.IsClassMethod() )
  1913. {
  1914. // TODO: Improve error message
  1915. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1916. r = -1;
  1917. }
  1918. // Make sure the expression can be implicitly converted to the parameter type
  1919. if( r >= 0 )
  1920. {
  1921. asCArray<int> funcs;
  1922. funcs.PushLast(func->id);
  1923. asCArray<asSOverloadCandidate> matches;
  1924. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1925. {
  1926. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1927. r = -1;
  1928. }
  1929. }
  1930. isCompilingDefaultArg = false;
  1931. script = origScript;
  1932. if( r < 0 )
  1933. {
  1934. asCString msg;
  1935. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1936. Error(msg, node);
  1937. anyErrors = true;
  1938. continue;
  1939. }
  1940. args[n] = asNEW(asCExprContext)(engine);
  1941. if( args[n] == 0 )
  1942. {
  1943. // Out of memory
  1944. reservedVariables.SetLength(prevReservedVars);
  1945. return -1;
  1946. }
  1947. MergeExprBytecodeAndType(args[n], &expr);
  1948. if (args[n]->exprNode)
  1949. {
  1950. // Disconnect the node from the parser, and tell the compiler to free it when complete
  1951. args[n]->exprNode->DisconnectParent();
  1952. nodesToFreeUponComplete.PushLast(args[n]->exprNode);
  1953. }
  1954. }
  1955. reservedVariables.SetLength(prevReservedVars);
  1956. return anyErrors ? -1 : 0;
  1957. }
  1958. asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asCExprContext*> &args, asCScriptNode *node, const char *name, asCArray<asSNamedArgument> *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1959. {
  1960. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1961. asUINT cost = 0;
  1962. asUINT n;
  1963. if( funcs.GetLength() > 0 )
  1964. {
  1965. // Check the number of parameters in the found functions
  1966. asUINT totalArgs = (asUINT)args.GetLength();
  1967. if( namedArgs != 0 )
  1968. totalArgs += (asUINT)namedArgs->GetLength();
  1969. for( n = 0; n < funcs.GetLength(); ++n )
  1970. {
  1971. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1972. if( desc->parameterTypes.GetLength() != totalArgs )
  1973. {
  1974. bool noMatch = true;
  1975. if( totalArgs < desc->parameterTypes.GetLength() )
  1976. {
  1977. // For virtual functions, the default args are defined in the real function of the object
  1978. if( desc->funcType == asFUNC_VIRTUAL )
  1979. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1980. // Count the number of default args
  1981. asUINT defaultArgs = 0;
  1982. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1983. if( desc->defaultArgs[d] )
  1984. defaultArgs++;
  1985. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1986. noMatch = false;
  1987. }
  1988. if( noMatch )
  1989. {
  1990. // remove it from the list
  1991. if( n == funcs.GetLength()-1 )
  1992. funcs.PopLast();
  1993. else
  1994. funcs[n] = funcs.PopLast();
  1995. n--;
  1996. }
  1997. }
  1998. }
  1999. // Match functions with the parameters, and discard those that do not match
  2000. asCArray<asSOverloadCandidate> matchingFuncs;
  2001. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  2002. for ( n = 0; n < funcs.GetLength(); ++n )
  2003. {
  2004. matchingFuncs[n].funcId = funcs[n];
  2005. matchingFuncs[n].cost = 0;
  2006. }
  2007. // Match positionally passed arguments
  2008. for( n = 0; n < args.GetLength(); ++n )
  2009. {
  2010. asCArray<asSOverloadCandidate> tempFuncs;
  2011. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  2012. // Intersect the found functions with the list of matching functions
  2013. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  2014. {
  2015. asUINT c;
  2016. for( c = 0; c < tempFuncs.GetLength(); c++ )
  2017. {
  2018. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  2019. {
  2020. // Sum argument cost
  2021. matchingFuncs[f].cost += tempFuncs[c].cost;
  2022. break;
  2023. } // End if match
  2024. }
  2025. // Was the function a match?
  2026. if( c == tempFuncs.GetLength() )
  2027. {
  2028. // No, remove it from the list
  2029. if( f == matchingFuncs.GetLength()-1 )
  2030. matchingFuncs.PopLast();
  2031. else
  2032. matchingFuncs[f] = matchingFuncs.PopLast();
  2033. f--;
  2034. }
  2035. }
  2036. }
  2037. // Match named arguments
  2038. if( namedArgs != 0 )
  2039. {
  2040. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  2041. {
  2042. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  2043. if( desc->funcType == asFUNC_VIRTUAL )
  2044. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  2045. // Match every named argument to an argument in the function
  2046. for( n = 0; n < namedArgs->GetLength(); ++n )
  2047. (*namedArgs)[n].match = asUINT(-1);
  2048. bool matchedAll = true;
  2049. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  2050. {
  2051. asUINT match = asUINT(-1);
  2052. for( n = 0; n < namedArgs->GetLength(); ++n )
  2053. {
  2054. asSNamedArgument &namedArg = (*namedArgs)[n];
  2055. if( desc->parameterNames[j] == namedArg.name )
  2056. {
  2057. namedArg.match = j;
  2058. match = n;
  2059. break;
  2060. }
  2061. }
  2062. // Check that every position is filled somehow
  2063. if( j >= args.GetLength() )
  2064. {
  2065. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  2066. {
  2067. // No argument was found for this, and there is no
  2068. // default, so it doesn't work.
  2069. matchedAll = false;
  2070. break;
  2071. }
  2072. }
  2073. else
  2074. {
  2075. if( match != asUINT(-1) )
  2076. {
  2077. // Can't name an argument that was already passed
  2078. matchedAll = false;
  2079. break;
  2080. }
  2081. }
  2082. }
  2083. // Check that every named argument was matched
  2084. if( matchedAll )
  2085. {
  2086. for( n = 0; n < namedArgs->GetLength(); ++n )
  2087. {
  2088. asSNamedArgument &named = (*namedArgs)[n];
  2089. if( named.match == asUINT(-1) )
  2090. {
  2091. matchedAll = false;
  2092. break;
  2093. }
  2094. // Add to the cost
  2095. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  2096. if( cost == asUINT(-1) )
  2097. {
  2098. matchedAll = false;
  2099. break;
  2100. }
  2101. matchingFuncs[i].cost += cost;
  2102. }
  2103. }
  2104. if( !matchedAll )
  2105. {
  2106. // Remove the function, we didn't match all the arguments.
  2107. if( i == matchingFuncs.GetLength()-1 )
  2108. matchingFuncs.PopLast();
  2109. else
  2110. matchingFuncs[i] = matchingFuncs.PopLast();
  2111. i--;
  2112. }
  2113. }
  2114. }
  2115. // Select the overload(s) with the lowest overall cost
  2116. funcs.SetLength(0);
  2117. asUINT bestCost = asUINT(-1);
  2118. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2119. {
  2120. cost = matchingFuncs[n].cost;
  2121. if( cost < bestCost )
  2122. {
  2123. funcs.SetLength(0);
  2124. bestCost = cost;
  2125. }
  2126. if( cost == bestCost )
  2127. funcs.PushLast( matchingFuncs[n].funcId );
  2128. }
  2129. // Cost returned is equivalent to the best cost discovered
  2130. cost = bestCost;
  2131. }
  2132. if( !isConstMethod )
  2133. FilterConst(funcs);
  2134. if( funcs.GetLength() != 1 && !silent )
  2135. {
  2136. // Build a readable string of the function with parameter types
  2137. bool attemptsPassingClassMethod = false;
  2138. asCString str;
  2139. if( scope != "" && scope != "::" )
  2140. str = scope + "::";
  2141. str += name;
  2142. str += "(";
  2143. for( n = 0; n < args.GetLength(); n++ )
  2144. {
  2145. if( n > 0 )
  2146. str += ", ";
  2147. if( args[n]->methodName != "" )
  2148. {
  2149. if( args[n]->IsClassMethod() )
  2150. {
  2151. attemptsPassingClassMethod = true;
  2152. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2153. str += "::";
  2154. }
  2155. str += args[n]->methodName;
  2156. }
  2157. else if (args[n]->IsAnonymousInitList())
  2158. {
  2159. str += "{...}";
  2160. }
  2161. else
  2162. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2163. }
  2164. if( namedArgs != 0 )
  2165. {
  2166. for( n = 0; n < namedArgs->GetLength(); n++ )
  2167. {
  2168. if( n > 0 || args.GetLength() )
  2169. str += ", ";
  2170. asSNamedArgument &named = (*namedArgs)[n];
  2171. str += named.name;
  2172. str += ": ";
  2173. if( named.ctx->methodName != "" )
  2174. str += named.ctx->methodName;
  2175. else
  2176. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2177. }
  2178. }
  2179. str += ")";
  2180. if( isConstMethod )
  2181. str += " const";
  2182. if( objectType && scope == "" )
  2183. str = objectType->name + "::" + str;
  2184. if( funcs.GetLength() == 0 )
  2185. {
  2186. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2187. Error(str, node);
  2188. if( attemptsPassingClassMethod )
  2189. {
  2190. // Class methods must use delegate objects
  2191. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2192. }
  2193. else
  2194. {
  2195. // Print the list of candidates
  2196. if( origFuncs.GetLength() > 0 )
  2197. {
  2198. int r = 0, c = 0;
  2199. asASSERT( node );
  2200. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2201. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2202. PrintMatchingFuncs(origFuncs, node, objectType);
  2203. }
  2204. }
  2205. }
  2206. else
  2207. {
  2208. asASSERT( attemptsPassingClassMethod == false );
  2209. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2210. Error(str, node);
  2211. PrintMatchingFuncs(funcs, node, objectType);
  2212. }
  2213. }
  2214. return cost;
  2215. }
  2216. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2217. {
  2218. if( node && node->nodeType == snAssignment )
  2219. {
  2220. int r = CompileAssignment(node, &compiledCtx);
  2221. if( r >= 0 )
  2222. {
  2223. // Must not have unused ambiguous names
  2224. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2225. {
  2226. // TODO: Should mention that the problem is the ambiguous name
  2227. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2228. return false;
  2229. }
  2230. // Must not have unused anonymous functions
  2231. if (compiledCtx.IsLambda())
  2232. {
  2233. // TODO: Should mention that the problem is the anonymous function
  2234. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2235. return false;
  2236. }
  2237. // Must not be a null handle
  2238. if (compiledCtx.type.dataType.IsNullHandle())
  2239. {
  2240. // TODO: Should mention that the problem is the null pointer
  2241. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2242. return false;
  2243. }
  2244. asCDataType newType = compiledCtx.type.dataType;
  2245. // Handle const qualifier on auto
  2246. if (type.IsReadOnly())
  2247. newType.MakeReadOnly(true);
  2248. else if (type.IsHandleToConst())
  2249. newType.MakeHandleToConst(true);
  2250. else if (newType.IsPrimitive())
  2251. newType.MakeReadOnly(false);
  2252. // Handle reference/value stuff
  2253. newType.MakeReference(false);
  2254. if (!newType.IsObjectHandle())
  2255. {
  2256. // We got a value object or an object reference.
  2257. // Turn the variable into a handle if specified
  2258. // as auto@, otherwise make it a 'value'.
  2259. if (type.IsHandleToAuto())
  2260. {
  2261. if (newType.MakeHandle(true) < 0)
  2262. {
  2263. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2264. return false;
  2265. }
  2266. }
  2267. }
  2268. // Implicit handle types should always be handles
  2269. if (newType.GetTypeInfo() &&
  2270. (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
  2271. newType.MakeHandle(true);
  2272. // For types that support handles auto should prefer handle
  2273. // as it is more efficient than making a copy
  2274. if( newType.SupportHandles() )
  2275. newType.MakeHandle(true);
  2276. type = newType;
  2277. return true;
  2278. }
  2279. return false;
  2280. }
  2281. else
  2282. {
  2283. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2284. type = asCDataType::CreatePrimitive(ttInt, false);
  2285. return false;
  2286. }
  2287. }
  2288. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2289. {
  2290. // Get the data type
  2291. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2292. // Declare all variables in this declaration
  2293. asCScriptNode *node = decl->firstChild->next;
  2294. while( node )
  2295. {
  2296. // If this is an auto type, we have to compile the assignment now to figure out the type
  2297. asCExprContext compiledCtx(engine);
  2298. bool preCompiled = false;
  2299. if (type.IsAuto())
  2300. {
  2301. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2302. if (!preCompiled)
  2303. {
  2304. // If it wasn't possible to determine the type from the expression then there
  2305. // is no need to continue with the initialization. The error was already reported
  2306. // in CompileAutoType.
  2307. return;
  2308. }
  2309. }
  2310. // Is the type allowed?
  2311. if( !type.CanBeInstantiated() )
  2312. {
  2313. asCString str;
  2314. if( type.IsAbstractClass() )
  2315. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2316. else if( type.IsInterface() )
  2317. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2318. else
  2319. // TODO: Improve error message to explain why
  2320. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2321. Error(str, node);
  2322. // Don't continue, as it will most likely lead to further
  2323. // errors that may just mislead the script writer
  2324. return;
  2325. }
  2326. // A shared object may not declare variables of non-shared types
  2327. if( outFunc->IsShared() )
  2328. {
  2329. asCTypeInfo *ot = type.GetTypeInfo();
  2330. if( ot && !ot->IsShared() )
  2331. {
  2332. asCString msg;
  2333. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2334. Error(msg, decl);
  2335. }
  2336. }
  2337. // Get the name of the identifier
  2338. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2339. // Verify that the name isn't used by a dynamic data type
  2340. // TODO: Must check against registered funcdefs too
  2341. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2342. {
  2343. asCString str;
  2344. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2345. Error(str, node);
  2346. }
  2347. int offset = AllocateVariable(type, false);
  2348. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2349. {
  2350. // TODO: It might be an out-of-memory too
  2351. asCString str;
  2352. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2353. Error(str, node);
  2354. // Don't continue after this error, as it will just
  2355. // lead to more errors that are likely false
  2356. return;
  2357. }
  2358. else
  2359. {
  2360. // Warn if this variable hides another variable in a higher scope
  2361. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2362. {
  2363. asCString str;
  2364. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2365. Warning(str, node);
  2366. }
  2367. }
  2368. // Add marker that the variable has been declared
  2369. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2370. outFunc->AddVariable(name, type, offset);
  2371. // Keep the node for the variable decl
  2372. asCScriptNode *varNode = node;
  2373. node = node->next;
  2374. if( node == 0 || node->nodeType == snIdentifier )
  2375. {
  2376. // Initialize with default constructor
  2377. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2378. }
  2379. else
  2380. {
  2381. // Compile the initialization expression
  2382. asQWORD constantValue = 0;
  2383. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2384. {
  2385. // Check if the variable should be marked as pure constant
  2386. if( type.IsPrimitive() && type.IsReadOnly() )
  2387. {
  2388. sVariable *v = variables->GetVariable(name.AddressOf());
  2389. v->isPureConstant = true;
  2390. v->constantValue = constantValue;
  2391. }
  2392. }
  2393. node = node->next;
  2394. }
  2395. }
  2396. bc->OptimizeLocally(tempVariableOffsets);
  2397. }
  2398. // Returns true if the initialization expression is a constant expression
  2399. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2400. {
  2401. bool isConstantExpression = false;
  2402. if( node && node->nodeType == snArgList )
  2403. {
  2404. // Make sure it is an object and not a handle
  2405. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2406. {
  2407. Error(TXT_MUST_BE_OBJECT, node);
  2408. }
  2409. else
  2410. {
  2411. // Compile the arguments
  2412. asCArray<asCExprContext *> args;
  2413. asCArray<asSNamedArgument> namedArgs;
  2414. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2415. {
  2416. // Find all constructors
  2417. asCArray<int> funcs;
  2418. asSTypeBehaviour *beh = type.GetBehaviour();
  2419. if( beh )
  2420. {
  2421. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2422. funcs = beh->factories;
  2423. else
  2424. funcs = beh->constructors;
  2425. }
  2426. asCString str = type.Format(outFunc->nameSpace);
  2427. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2428. if( funcs.GetLength() == 1 )
  2429. {
  2430. // Add the default values for arguments not explicitly supplied
  2431. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2432. if( r == asSUCCESS )
  2433. {
  2434. asCExprContext ctx(engine);
  2435. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2436. {
  2437. if( isVarGlobOrMem == 0 )
  2438. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2439. else
  2440. {
  2441. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2442. ctx.bc.Instr(asBC_RDSPtr);
  2443. if( isVarGlobOrMem == 1 )
  2444. {
  2445. // Store the returned handle in the global variable
  2446. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2447. }
  2448. else
  2449. {
  2450. // Store the returned handle in the member
  2451. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2452. ctx.bc.Instr(asBC_RDSPtr);
  2453. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2454. }
  2455. if( type.IsFuncdef())
  2456. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2457. else
  2458. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2459. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2460. }
  2461. // Pop the reference left by the function call
  2462. ctx.bc.Instr(asBC_PopPtr);
  2463. }
  2464. else
  2465. {
  2466. bool onHeap = false;
  2467. if( isVarGlobOrMem == 0 )
  2468. {
  2469. // When the object is allocated on the heap, the address where the
  2470. // reference will be stored must be pushed on the stack before the
  2471. // arguments. This reference on the stack is safe, even if the script
  2472. // is suspended during the evaluation of the arguments.
  2473. onHeap = IsVariableOnHeap(offset);
  2474. if( onHeap )
  2475. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2476. }
  2477. else if( isVarGlobOrMem == 1 )
  2478. {
  2479. // Push the address of the location where the variable will be stored on the stack.
  2480. // This reference is safe, because the addresses of the global variables cannot change.
  2481. onHeap = true;
  2482. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2483. }
  2484. else
  2485. {
  2486. // Value types may be allocated inline if they are POD types
  2487. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2488. if( onHeap )
  2489. {
  2490. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2491. ctx.bc.Instr(asBC_RDSPtr);
  2492. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2493. }
  2494. }
  2495. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2496. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2497. // When the object is allocated on the stack, the address to the
  2498. // object is pushed on the stack after the arguments as the object pointer
  2499. if( !onHeap )
  2500. {
  2501. if( isVarGlobOrMem == 2 )
  2502. {
  2503. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2504. ctx.bc.Instr(asBC_RDSPtr);
  2505. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2506. }
  2507. else
  2508. {
  2509. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2510. }
  2511. }
  2512. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2513. if( isVarGlobOrMem == 0 )
  2514. {
  2515. // Mark the object in the local variable as initialized
  2516. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2517. }
  2518. }
  2519. bc->AddCode(&ctx.bc);
  2520. }
  2521. }
  2522. }
  2523. // Cleanup
  2524. for( asUINT n = 0; n < args.GetLength(); n++ )
  2525. if( args[n] )
  2526. {
  2527. asDELETE(args[n], asCExprContext);
  2528. }
  2529. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2530. if( namedArgs[n].ctx )
  2531. {
  2532. asDELETE(namedArgs[n].ctx, asCExprContext);
  2533. }
  2534. }
  2535. }
  2536. else if( node && node->nodeType == snInitList )
  2537. {
  2538. asCExprValue ti;
  2539. ti.Set(type);
  2540. ti.isVariable = (isVarGlobOrMem == 0);
  2541. ti.isTemporary = false;
  2542. ti.stackOffset = (short)offset;
  2543. ti.isLValue = true;
  2544. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2545. }
  2546. else if( node && node->nodeType == snAssignment )
  2547. {
  2548. // Compile the expression
  2549. asCExprContext newExpr(engine);
  2550. asCExprContext* expr;
  2551. int r = 0;
  2552. if( preCompiled )
  2553. {
  2554. expr = preCompiled;
  2555. }
  2556. else
  2557. {
  2558. expr = &newExpr;
  2559. r = CompileAssignment(node, expr);
  2560. }
  2561. // handles initialized with null doesn't need any bytecode
  2562. // since handles will be initialized to null by default anyway
  2563. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2564. return false;
  2565. // Look for appropriate constructor
  2566. asCArray<int> funcs;
  2567. asCArray<asCExprContext *> args;
  2568. // Handles must use the handle assignment operation.
  2569. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2570. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2571. // Only do this if the expression is of the same type, as the expression is an assignment
  2572. // and an initialization constructor may not have the same meaning.
  2573. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2574. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2575. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2576. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2577. {
  2578. asSTypeBehaviour *beh = type.GetBehaviour();
  2579. if( beh )
  2580. {
  2581. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2582. funcs = beh->factories;
  2583. else
  2584. funcs = beh->constructors;
  2585. }
  2586. asCString str = type.Format(outFunc->nameSpace);
  2587. args.PushLast(expr);
  2588. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2589. // Make sure the argument is of the right type (and not just compatible with the expression)
  2590. if (funcs.GetLength() == 1)
  2591. {
  2592. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2593. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2594. funcs.PopLast();
  2595. }
  2596. }
  2597. if( funcs.GetLength() == 1 )
  2598. {
  2599. // Use the constructor
  2600. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2601. // Add the default values for arguments not explicitly supplied
  2602. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2603. if( r == asSUCCESS )
  2604. {
  2605. asCExprContext ctx(engine);
  2606. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2607. {
  2608. if( isVarGlobOrMem == 0 )
  2609. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2610. else
  2611. {
  2612. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2613. ctx.bc.Instr(asBC_RDSPtr);
  2614. if( isVarGlobOrMem == 1 )
  2615. {
  2616. // Store the returned handle in the global variable
  2617. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2618. }
  2619. else
  2620. {
  2621. // Store the returned handle in the member
  2622. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2623. ctx.bc.Instr(asBC_RDSPtr);
  2624. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2625. }
  2626. if( type.IsFuncdef() )
  2627. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2628. else
  2629. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2630. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2631. }
  2632. // Pop the reference left by the function call
  2633. ctx.bc.Instr(asBC_PopPtr);
  2634. }
  2635. else
  2636. {
  2637. bool onHeap = false;
  2638. if( isVarGlobOrMem == 0 )
  2639. {
  2640. // When the object is allocated on the heap, the address where the
  2641. // reference will be stored must be pushed on the stack before the
  2642. // arguments. This reference on the stack is safe, even if the script
  2643. // is suspended during the evaluation of the arguments.
  2644. onHeap = IsVariableOnHeap(offset);
  2645. if( onHeap )
  2646. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2647. }
  2648. else if( isVarGlobOrMem == 1 )
  2649. {
  2650. // Push the address of the location where the variable will be stored on the stack.
  2651. // This reference is safe, because the addresses of the global variables cannot change.
  2652. onHeap = true;
  2653. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2654. }
  2655. else
  2656. {
  2657. // Value types may be allocated inline if they are POD types
  2658. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2659. if( onHeap )
  2660. {
  2661. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2662. ctx.bc.Instr(asBC_RDSPtr);
  2663. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2664. }
  2665. }
  2666. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2667. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2668. // When the object is allocated on the stack, the address to the
  2669. // object is pushed on the stack after the arguments as the object pointer
  2670. if( !onHeap )
  2671. {
  2672. if( isVarGlobOrMem == 2 )
  2673. {
  2674. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2675. ctx.bc.Instr(asBC_RDSPtr);
  2676. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2677. }
  2678. else
  2679. {
  2680. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2681. }
  2682. }
  2683. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2684. if( isVarGlobOrMem == 0 )
  2685. {
  2686. // Mark the object in the local variable as initialized
  2687. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2688. }
  2689. }
  2690. bc->AddCode(&ctx.bc);
  2691. }
  2692. }
  2693. else
  2694. {
  2695. // Call the default constructor, then call the assignment operator
  2696. asCExprContext ctx(engine);
  2697. // Call the default constructor here
  2698. if( isVarGlobOrMem == 0 )
  2699. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2700. else if( isVarGlobOrMem == 1 )
  2701. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2702. else if( isVarGlobOrMem == 2 )
  2703. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2704. if( r >= 0 )
  2705. {
  2706. if( type.IsPrimitive() )
  2707. {
  2708. if( type.IsReadOnly() && expr->type.isConstant )
  2709. {
  2710. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2711. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2712. isConstantExpression = true;
  2713. *constantValue = expr->type.GetConstantData();
  2714. }
  2715. asCExprContext lctx(engine);
  2716. if( isVarGlobOrMem == 0 )
  2717. lctx.type.SetVariable(type, offset, false);
  2718. else if( isVarGlobOrMem == 1 )
  2719. {
  2720. lctx.type.Set(type);
  2721. lctx.type.dataType.MakeReference(true);
  2722. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2723. // we skip this as the bytecode won't be used anyway, only the constant value
  2724. if( offset >= 0 )
  2725. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2726. }
  2727. else
  2728. {
  2729. asASSERT( isVarGlobOrMem == 2 );
  2730. lctx.type.Set(type);
  2731. lctx.type.dataType.MakeReference(true);
  2732. // Load the reference of the primitive member into the register
  2733. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2734. lctx.bc.Instr(asBC_RDSPtr);
  2735. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2736. lctx.bc.Instr(asBC_PopRPtr);
  2737. }
  2738. lctx.type.dataType.MakeReadOnly(false);
  2739. lctx.type.isLValue = true;
  2740. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2741. ProcessDeferredParams(&ctx);
  2742. }
  2743. else
  2744. {
  2745. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2746. // just the copy constructor. Only if no appropriate constructor is
  2747. // available should the assignment operator be used.
  2748. asCExprContext lexpr(engine);
  2749. lexpr.type.Set(type);
  2750. if( isVarGlobOrMem == 0 )
  2751. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2752. else if( isVarGlobOrMem == 1 )
  2753. lexpr.type.dataType.MakeReference(true);
  2754. else if( isVarGlobOrMem == 2 )
  2755. {
  2756. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2757. lexpr.type.dataType.MakeReference(true);
  2758. }
  2759. // Allow initialization of constant variables
  2760. lexpr.type.dataType.MakeReadOnly(false);
  2761. if( type.IsObjectHandle() )
  2762. lexpr.type.isExplicitHandle = true;
  2763. if( isVarGlobOrMem == 0 )
  2764. {
  2765. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2766. lexpr.type.stackOffset = (short)offset;
  2767. lexpr.type.isVariable = true;
  2768. }
  2769. else if( isVarGlobOrMem == 1 )
  2770. {
  2771. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2772. }
  2773. else
  2774. {
  2775. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2776. lexpr.bc.Instr(asBC_RDSPtr);
  2777. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2778. lexpr.type.stackOffset = -1;
  2779. }
  2780. lexpr.type.isLValue = true;
  2781. // If left expression resolves into a registered type
  2782. // check if the assignment operator is overloaded, and check
  2783. // the type of the right hand expression. If none is found
  2784. // the default action is a direct copy if it is the same type
  2785. // and a simple assignment.
  2786. bool assigned = false;
  2787. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2788. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2789. {
  2790. bool useHndlAssign = false;
  2791. if (lexpr.type.dataType.IsHandleToAsHandleType())
  2792. {
  2793. useHndlAssign = true;
  2794. // Make sure the right hand expression is treated as a handle
  2795. if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() )
  2796. {
  2797. // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
  2798. // Convert the expression to a handle
  2799. if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
  2800. {
  2801. asCDataType to = expr->type.dataType;
  2802. to.MakeHandle(true);
  2803. to.MakeReference(true);
  2804. to.MakeHandleToConst(expr->type.dataType.IsReadOnly());
  2805. ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false);
  2806. asASSERT(expr->type.dataType.IsObjectHandle());
  2807. }
  2808. else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
  2809. {
  2810. // For the ASHANDLE type we'll simply set the expression as a handle
  2811. expr->type.dataType.MakeHandle(true);
  2812. }
  2813. if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles())
  2814. {
  2815. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  2816. }
  2817. expr->type.isExplicitHandle = true;
  2818. }
  2819. }
  2820. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2821. if( assigned )
  2822. {
  2823. // Pop the resulting value
  2824. if( !ctx.type.dataType.IsPrimitive() )
  2825. ctx.bc.Instr(asBC_PopPtr);
  2826. // Release the argument
  2827. ProcessDeferredParams(&ctx);
  2828. // Release temporary variable that may be allocated by the overloaded operator
  2829. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2830. }
  2831. }
  2832. if( !assigned )
  2833. {
  2834. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2835. // If the expression is constant and the variable also is constant
  2836. // then mark the variable as pure constant. This will allow the compiler
  2837. // to optimize expressions with this variable.
  2838. if( type.IsReadOnly() && expr->type.isConstant )
  2839. {
  2840. isConstantExpression = true;
  2841. *constantValue = expr->type.GetConstantQW();
  2842. }
  2843. // Add expression code to bytecode
  2844. MergeExprBytecode(&ctx, expr);
  2845. // Add byte code for storing value of expression in variable
  2846. ctx.bc.AddCode(&lexpr.bc);
  2847. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2848. // Release temporary variables used by expression
  2849. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2850. ctx.bc.Instr(asBC_PopPtr);
  2851. ProcessDeferredParams(&ctx);
  2852. }
  2853. }
  2854. }
  2855. bc->AddCode(&ctx.bc);
  2856. }
  2857. }
  2858. else
  2859. {
  2860. asASSERT( node == 0 );
  2861. // Call the default constructor here, as no explicit initialization is done
  2862. if( isVarGlobOrMem == 0 )
  2863. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2864. else if( isVarGlobOrMem == 1 )
  2865. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2866. else if( isVarGlobOrMem == 2 )
  2867. {
  2868. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2869. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2870. else
  2871. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2872. }
  2873. }
  2874. return isConstantExpression;
  2875. }
  2876. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2877. {
  2878. // Check if the type supports initialization lists
  2879. if( var->dataType.GetTypeInfo() == 0 ||
  2880. var->dataType.GetBehaviour()->listFactory == 0 )
  2881. {
  2882. asCString str;
  2883. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2884. Error(str, node);
  2885. return;
  2886. }
  2887. // Construct the buffer with the elements
  2888. // Find the list factory
  2889. int funcId = var->dataType.GetBehaviour()->listFactory;
  2890. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2891. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2892. // for small buffers so that the dynamic allocation is skipped
  2893. // Create a new special object type for the lists. Both asCRestore and the
  2894. // context exception handler will need this to know how to parse the buffer.
  2895. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2896. // Allocate a temporary variable to hold the pointer to the buffer
  2897. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2898. asUINT bufferSize = 0;
  2899. // Evaluate all elements of the list
  2900. asCExprContext valueExpr(engine);
  2901. asCScriptNode *el = node;
  2902. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2903. int elementsInSubList = -1;
  2904. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2905. asASSERT( r || patternNode == 0 );
  2906. if (r < 0)
  2907. {
  2908. asCString msg;
  2909. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2910. Error(msg, node);
  2911. }
  2912. // After all values have been evaluated we know the final size of the buffer
  2913. asCExprContext allocExpr(engine);
  2914. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2915. // Merge the bytecode into the final sequence
  2916. bc->AddCode(&allocExpr.bc);
  2917. bc->AddCode(&valueExpr.bc);
  2918. // The object itself is the last to be created and will receive the pointer to the buffer
  2919. asCArray<asCExprContext *> args;
  2920. asCExprContext arg1(engine);
  2921. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2922. arg1.type.dataType.MakeReference(true);
  2923. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2924. args.PushLast(&arg1);
  2925. asCExprContext ctx(engine);
  2926. if( var->isVariable )
  2927. {
  2928. asASSERT( isVarGlobOrMem == 0 );
  2929. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2930. {
  2931. ctx.bc.AddCode(&arg1.bc);
  2932. // Call factory and store the handle in the given variable
  2933. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2934. ctx.bc.Instr(asBC_PopPtr);
  2935. }
  2936. else
  2937. {
  2938. // Call the constructor
  2939. // When the object is allocated on the heap, the address where the
  2940. // reference will be stored must be pushed on the stack before the
  2941. // arguments. This reference on the stack is safe, even if the script
  2942. // is suspended during the evaluation of the arguments.
  2943. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2944. if( onHeap )
  2945. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2946. ctx.bc.AddCode(&arg1.bc);
  2947. // When the object is allocated on the stack, the address to the
  2948. // object is pushed on the stack after the arguments as the object pointer
  2949. if( !onHeap )
  2950. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2951. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2952. // Mark the object in the local variable as initialized
  2953. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2954. }
  2955. }
  2956. else
  2957. {
  2958. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2959. {
  2960. ctx.bc.AddCode(&arg1.bc);
  2961. PerformFunctionCall(funcId, &ctx, false, &args);
  2962. ctx.bc.Instr(asBC_RDSPtr);
  2963. if( isVarGlobOrMem == 1 )
  2964. {
  2965. // Store the returned handle in the global variable
  2966. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2967. }
  2968. else
  2969. {
  2970. // Store the returned handle in the member
  2971. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2972. ctx.bc.Instr(asBC_RDSPtr);
  2973. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2974. }
  2975. if (var->dataType.IsFuncdef())
  2976. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2977. else
  2978. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2979. ctx.bc.Instr(asBC_PopPtr);
  2980. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2981. }
  2982. else
  2983. {
  2984. bool onHeap = true;
  2985. // Put the address where the object pointer will be placed on the stack
  2986. if( isVarGlobOrMem == 1 )
  2987. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2988. else
  2989. {
  2990. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  2991. if( onHeap )
  2992. {
  2993. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2994. ctx.bc.Instr(asBC_RDSPtr);
  2995. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2996. }
  2997. }
  2998. // Add the address of the list buffer as the argument
  2999. ctx.bc.AddCode(&arg1.bc);
  3000. if( !onHeap )
  3001. {
  3002. ctx.bc.InstrSHORT(asBC_PSF, 0);
  3003. ctx.bc.Instr(asBC_RDSPtr);
  3004. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  3005. }
  3006. // Call the ALLOC instruction to allocate memory and invoke constructor
  3007. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  3008. }
  3009. }
  3010. bc->AddCode(&ctx.bc);
  3011. // Free the temporary buffer. The FREE instruction will make sure to destroy
  3012. // each element in the buffer so there is no need to do this manually
  3013. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  3014. ReleaseTemporaryVariable(bufferVar, bc);
  3015. }
  3016. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  3017. {
  3018. if( patternNode->type == asLPT_START )
  3019. {
  3020. if( valueNode == 0 || valueNode->nodeType != snInitList )
  3021. {
  3022. Error(TXT_EXPECTED_LIST, valueNode);
  3023. return -1;
  3024. }
  3025. // Compile all values until asLPT_END
  3026. patternNode = patternNode->next;
  3027. asCScriptNode *node = valueNode->firstChild;
  3028. while( patternNode->type != asLPT_END )
  3029. {
  3030. // Check for missing value here, else the error reporting will not have a source position to report the error for
  3031. if( node == 0 && patternNode->type == asLPT_TYPE )
  3032. {
  3033. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  3034. return -1;
  3035. }
  3036. asCScriptNode *errNode = node;
  3037. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  3038. if( r < 0 ) return r;
  3039. if( r == 1 )
  3040. {
  3041. asASSERT( engine->ep.disallowEmptyListElements );
  3042. // Empty elements in the middle are not allowed
  3043. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3044. }
  3045. asASSERT( patternNode );
  3046. }
  3047. if( node )
  3048. {
  3049. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  3050. return -1;
  3051. }
  3052. // Move to the next node
  3053. valueNode = valueNode->next;
  3054. patternNode = patternNode->next;
  3055. }
  3056. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  3057. {
  3058. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  3059. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  3060. asEListPatternNodeType repeatType = patternNode->type;
  3061. asCScriptNode *firstValue = valueNode;
  3062. // The following values will be repeated N times
  3063. patternNode = patternNode->next;
  3064. // Keep track of the patternNode so it can be reset
  3065. asSListPatternNode *nextNode = patternNode;
  3066. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  3067. if( bufferSize & 0x3 )
  3068. bufferSize += 4 - (bufferSize & 0x3);
  3069. // The first dword will hold the number of elements in the list
  3070. asDWORD currSize = bufferSize;
  3071. bufferSize += 4;
  3072. asUINT countElements = 0;
  3073. int elementsInSubSubList = -1;
  3074. asCExprContext ctx(engine);
  3075. while( valueNode )
  3076. {
  3077. patternNode = nextNode;
  3078. asCScriptNode *errNode = valueNode;
  3079. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  3080. if( r < 0 ) return r;
  3081. if( r == 0 )
  3082. countElements++;
  3083. else
  3084. {
  3085. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  3086. if( valueNode )
  3087. {
  3088. // Empty elements in the middle are not allowed
  3089. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3090. }
  3091. }
  3092. }
  3093. if( countElements == 0 )
  3094. {
  3095. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  3096. patternNode = nextNode;
  3097. if( patternNode->type == asLPT_TYPE )
  3098. patternNode = patternNode->next;
  3099. else if( patternNode->type == asLPT_START )
  3100. {
  3101. int subCount = 1;
  3102. do
  3103. {
  3104. patternNode = patternNode->next;
  3105. if( patternNode->type == asLPT_START )
  3106. subCount++;
  3107. else if( patternNode->type == asLPT_END )
  3108. subCount--;
  3109. } while( subCount > 0 );
  3110. patternNode = patternNode->next;
  3111. }
  3112. }
  3113. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  3114. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  3115. {
  3116. if( countElements < asUINT(elementsInSubList) )
  3117. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  3118. else
  3119. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  3120. return -1;
  3121. }
  3122. else
  3123. {
  3124. // Return to caller the amount of elments in this sublist
  3125. elementsInSubList = countElements;
  3126. }
  3127. // The first dword in the buffer will hold the number of elements
  3128. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  3129. // Add the values
  3130. bcInit.AddCode(&ctx.bc);
  3131. }
  3132. else if( patternNode->type == asLPT_TYPE )
  3133. {
  3134. bool isEmpty = false;
  3135. // Determine the size of the element
  3136. asUINT size = 0;
  3137. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  3138. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  3139. {
  3140. asCExprContext lctx(engine);
  3141. asCExprContext rctx(engine);
  3142. if( valueNode->nodeType == snAssignment )
  3143. {
  3144. // Compile the assignment expression
  3145. CompileAssignment(valueNode, &rctx);
  3146. if( dt.GetTokenType() == ttQuestion )
  3147. {
  3148. // Make sure the type is not ambiguous
  3149. DetermineSingleFunc(&rctx, valueNode);
  3150. // We now know the type
  3151. dt = rctx.type.dataType;
  3152. dt.MakeReadOnly(false);
  3153. dt.MakeReference(false);
  3154. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3155. if( bufferSize & 0x3 )
  3156. bufferSize += 4 - (bufferSize & 0x3);
  3157. // When value assignment for reference types us disabled, make sure all ref types are passed in as handles
  3158. if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles())
  3159. dt.MakeHandle(true);
  3160. // Place the type id in the buffer
  3161. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3162. bufferSize += 4;
  3163. }
  3164. }
  3165. else if( valueNode->nodeType == snInitList )
  3166. {
  3167. if( dt.GetTokenType() == ttQuestion )
  3168. {
  3169. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3170. asCString str;
  3171. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3172. Error(str.AddressOf(), valueNode);
  3173. rctx.type.SetDummy();
  3174. dt = rctx.type.dataType;
  3175. }
  3176. else
  3177. {
  3178. // Allocate a temporary variable that will be initialized with the list
  3179. int offset = AllocateVariable(dt, true);
  3180. rctx.type.Set(dt);
  3181. rctx.type.isVariable = true;
  3182. rctx.type.isTemporary = true;
  3183. rctx.type.stackOffset = (short)offset;
  3184. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3185. // Put the object on the stack
  3186. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  3187. // It is a reference that we place on the stack
  3188. rctx.type.dataType.MakeReference(true);
  3189. }
  3190. }
  3191. // Determine size of the element
  3192. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3193. size = dt.GetSizeInMemoryBytes();
  3194. else
  3195. size = AS_PTR_SIZE*4;
  3196. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3197. if( size >= 4 && (bufferSize & 0x3) )
  3198. bufferSize += 4 - (bufferSize & 0x3);
  3199. // Compile the lvalue
  3200. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3201. lctx.type.Set(dt);
  3202. lctx.type.isLValue = true;
  3203. if( dt.IsPrimitive() )
  3204. {
  3205. lctx.bc.Instr(asBC_PopRPtr);
  3206. lctx.type.dataType.MakeReference(true);
  3207. }
  3208. else if( dt.IsObjectHandle() ||
  3209. dt.GetTypeInfo()->flags & asOBJ_REF )
  3210. {
  3211. lctx.type.isExplicitHandle = true;
  3212. lctx.type.dataType.MakeReference(true);
  3213. }
  3214. else
  3215. {
  3216. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3217. // Make sure the object has been constructed before the assignment
  3218. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3219. asSTypeBehaviour *beh = dt.GetBehaviour();
  3220. int func = 0;
  3221. if( beh ) func = beh->construct;
  3222. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3223. {
  3224. asCString str;
  3225. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3226. Error(str, valueNode);
  3227. }
  3228. else if( func )
  3229. {
  3230. // Call the constructor as a normal function
  3231. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3232. asCExprContext ctx(engine);
  3233. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3234. bcInit.AddCode(&ctx.bc);
  3235. }
  3236. }
  3237. if( lctx.type.dataType.IsNullHandle() )
  3238. {
  3239. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3240. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3241. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3242. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3243. }
  3244. else
  3245. {
  3246. asCExprContext ctx(engine);
  3247. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3248. if( !ctx.type.dataType.IsPrimitive() )
  3249. ctx.bc.Instr(asBC_PopPtr);
  3250. // Release temporary variables used by expression
  3251. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3252. ProcessDeferredParams(&ctx);
  3253. bcInit.AddCode(&ctx.bc);
  3254. }
  3255. }
  3256. else
  3257. {
  3258. if( builder->engine->ep.disallowEmptyListElements )
  3259. {
  3260. // Empty elements are not allowed, except if it is the last in the list
  3261. isEmpty = true;
  3262. }
  3263. else
  3264. {
  3265. // There is no specific value so we need to fill it with a default value
  3266. if( dt.GetTokenType() == ttQuestion )
  3267. {
  3268. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3269. if( bufferSize & 0x3 )
  3270. bufferSize += 4 - (bufferSize & 0x3);
  3271. // Place the type id for a null handle in the buffer
  3272. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3273. bufferSize += 4;
  3274. dt = asCDataType::CreateNullHandle();
  3275. // No need to initialize the handle as the buffer is already initialized with zeroes
  3276. }
  3277. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3278. {
  3279. // For value types with default constructor we need to call the constructor
  3280. asSTypeBehaviour *beh = dt.GetBehaviour();
  3281. int func = 0;
  3282. if( beh ) func = beh->construct;
  3283. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3284. {
  3285. asCString str;
  3286. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3287. Error(str, valueNode);
  3288. }
  3289. else if( func )
  3290. {
  3291. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3292. if( bufferSize & 0x3 )
  3293. bufferSize += 4 - (bufferSize & 0x3);
  3294. // Call the constructor as a normal function
  3295. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3296. asCExprContext ctx(engine);
  3297. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3298. bcInit.AddCode(&ctx.bc);
  3299. }
  3300. }
  3301. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3302. {
  3303. // For ref types (not handles) we need to call the default factory
  3304. asSTypeBehaviour *beh = dt.GetBehaviour();
  3305. int func = 0;
  3306. if( beh ) func = beh->factory;
  3307. if( func == 0 )
  3308. {
  3309. asCString str;
  3310. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3311. Error(str, valueNode);
  3312. }
  3313. else if( func )
  3314. {
  3315. asCExprContext rctx(engine);
  3316. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3317. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3318. if( bufferSize & 0x3 )
  3319. bufferSize += 4 - (bufferSize & 0x3);
  3320. asCExprContext lctx(engine);
  3321. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3322. lctx.type.Set(dt);
  3323. lctx.type.isLValue = true;
  3324. lctx.type.isExplicitHandle = true;
  3325. lctx.type.dataType.MakeReference(true);
  3326. asCExprContext ctx(engine);
  3327. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3328. if( !ctx.type.dataType.IsPrimitive() )
  3329. ctx.bc.Instr(asBC_PopPtr);
  3330. // Release temporary variables used by expression
  3331. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3332. ProcessDeferredParams(&ctx);
  3333. bcInit.AddCode(&ctx.bc);
  3334. }
  3335. }
  3336. }
  3337. }
  3338. if( !isEmpty )
  3339. {
  3340. // Determine size of the element
  3341. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3342. size = dt.GetSizeInMemoryBytes();
  3343. else
  3344. size = AS_PTR_SIZE*4;
  3345. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3346. bufferSize += size;
  3347. }
  3348. // Move to the next element
  3349. patternNode = patternNode->next;
  3350. valueNode = valueNode->next;
  3351. if( isEmpty )
  3352. {
  3353. // The caller will determine if the empty element should be ignored or not
  3354. return 1;
  3355. }
  3356. }
  3357. else
  3358. asASSERT( false );
  3359. return 0;
  3360. }
  3361. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3362. {
  3363. // Don't clear the hasReturn flag if this is an empty statement
  3364. // to avoid false errors of 'not all paths return'
  3365. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3366. *hasReturn = false;
  3367. if (statement->nodeType == snStatementBlock)
  3368. CompileStatementBlock(statement, true, hasReturn, bc);
  3369. else if (statement->nodeType == snIf)
  3370. CompileIfStatement(statement, hasReturn, bc);
  3371. else if (statement->nodeType == snFor)
  3372. CompileForStatement(statement, bc);
  3373. else if (statement->nodeType == snWhile)
  3374. CompileWhileStatement(statement, bc);
  3375. else if (statement->nodeType == snDoWhile)
  3376. CompileDoWhileStatement(statement, bc);
  3377. else if (statement->nodeType == snExpressionStatement)
  3378. CompileExpressionStatement(statement, bc);
  3379. else if (statement->nodeType == snBreak)
  3380. CompileBreakStatement(statement, bc);
  3381. else if (statement->nodeType == snContinue)
  3382. CompileContinueStatement(statement, bc);
  3383. else if (statement->nodeType == snSwitch)
  3384. CompileSwitchStatement(statement, hasReturn, bc);
  3385. else if (statement->nodeType == snTryCatch)
  3386. CompileTryCatch(statement, hasReturn, bc);
  3387. else if (statement->nodeType == snReturn)
  3388. {
  3389. CompileReturnStatement(statement, bc);
  3390. *hasReturn = true;
  3391. }
  3392. else
  3393. asASSERT(false);
  3394. }
  3395. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3396. {
  3397. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3398. // Reserve label for break statements
  3399. int breakLabel = nextLabel++;
  3400. breakLabels.PushLast(breakLabel);
  3401. // Add a variable scope that will be used by CompileBreak
  3402. // to know where to stop deallocating variables
  3403. AddVariableScope(true, false);
  3404. //---------------------------
  3405. // Compile the switch expression
  3406. //-------------------------------
  3407. // Compile the switch expression
  3408. asCExprContext expr(engine);
  3409. CompileAssignment(snode->firstChild, &expr);
  3410. // Verify that the expression is a primitive type
  3411. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3412. {
  3413. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3414. return;
  3415. }
  3416. if( ProcessPropertyGetAccessor(&expr, snode) < 0 )
  3417. return;
  3418. // TODO: Need to support 64bit integers
  3419. // Convert the expression to a 32bit variable
  3420. asCDataType to;
  3421. if( expr.type.dataType.IsIntegerType() )
  3422. to.SetTokenType(ttInt);
  3423. else if( expr.type.dataType.IsUnsignedType() )
  3424. to.SetTokenType(ttUInt);
  3425. // Make sure the value is in a variable
  3426. if( expr.type.dataType.IsReference() )
  3427. ConvertToVariable(&expr);
  3428. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3429. ConvertToVariable(&expr);
  3430. int offset = expr.type.stackOffset;
  3431. ProcessDeferredParams(&expr);
  3432. //-------------------------------
  3433. // Determine case values and labels
  3434. //--------------------------------
  3435. // Remember the first label so that we can later pass the
  3436. // correct label to each CompileCase()
  3437. int firstCaseLabel = nextLabel;
  3438. int defaultLabel = 0;
  3439. asCArray<int> caseValues;
  3440. asCArray<int> caseLabels;
  3441. // Compile all case comparisons and make them jump to the right label
  3442. asCScriptNode *cnode = snode->firstChild->next;
  3443. while( cnode )
  3444. {
  3445. // Each case should have a constant expression
  3446. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3447. {
  3448. // Compile expression
  3449. asCExprContext c(engine);
  3450. CompileExpression(cnode->firstChild, &c);
  3451. // Verify that the result is a constant
  3452. if( !c.type.isConstant )
  3453. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3454. // Verify that the result is an integral number
  3455. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3456. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3457. else
  3458. {
  3459. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3460. // Has this case been declared already?
  3461. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3462. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3463. // TODO: Optimize: We can insert the numbers sorted already
  3464. // Store constant for later use
  3465. caseValues.PushLast(c.type.GetConstantDW());
  3466. // Reserve label for this case
  3467. caseLabels.PushLast(nextLabel++);
  3468. }
  3469. }
  3470. else
  3471. {
  3472. // TODO: It shouldn't be necessary for the default case to be the last one.
  3473. // Is default the last case?
  3474. if( cnode->next )
  3475. {
  3476. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3477. break;
  3478. }
  3479. // Reserve label for this case
  3480. defaultLabel = nextLabel++;
  3481. }
  3482. cnode = cnode->next;
  3483. }
  3484. // check for empty switch
  3485. if (caseValues.GetLength() == 0)
  3486. {
  3487. Error(TXT_EMPTY_SWITCH, snode);
  3488. return;
  3489. }
  3490. if( defaultLabel == 0 )
  3491. defaultLabel = breakLabel;
  3492. //---------------------------------
  3493. // Output the optimized case comparisons
  3494. // with jumps to the case code
  3495. //------------------------------------
  3496. // Sort the case values by increasing value. Do the sort together with the labels
  3497. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3498. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3499. {
  3500. for( int bck = fwd - 1; bck >= 0; bck-- )
  3501. {
  3502. int bckp = bck + 1;
  3503. if( caseValues[bck] > caseValues[bckp] )
  3504. {
  3505. // Swap the values in both arrays
  3506. int swap = caseValues[bckp];
  3507. caseValues[bckp] = caseValues[bck];
  3508. caseValues[bck] = swap;
  3509. swap = caseLabels[bckp];
  3510. caseLabels[bckp] = caseLabels[bck];
  3511. caseLabels[bck] = swap;
  3512. }
  3513. else
  3514. break;
  3515. }
  3516. }
  3517. // Find ranges of consecutive numbers
  3518. asCArray<int> ranges;
  3519. ranges.PushLast(0);
  3520. asUINT n;
  3521. for( n = 1; n < caseValues.GetLength(); ++n )
  3522. {
  3523. // We can join numbers that are less than 5 numbers
  3524. // apart since the output code will still be smaller
  3525. if( caseValues[n] > caseValues[n-1] + 5 )
  3526. ranges.PushLast(n);
  3527. }
  3528. // If the value is larger than the largest case value, jump to default
  3529. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3530. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3531. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3532. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3533. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3534. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3535. // binary search instead of a linear search through the ranges
  3536. // For each range
  3537. int range;
  3538. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3539. {
  3540. // Find the largest value in this range
  3541. int maxRange = caseValues[ranges[range]];
  3542. int index = ranges[range];
  3543. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3544. maxRange = caseValues[index];
  3545. // If there are only 2 numbers then it is better to compare them directly
  3546. if( index - ranges[range] > 2 )
  3547. {
  3548. // If the value is smaller than the smallest case value in the range, jump to default
  3549. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3550. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3551. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3552. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3553. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3554. int nextRangeLabel = nextLabel++;
  3555. // If this is the last range we don't have to make this test
  3556. if( range < (int)ranges.GetLength() - 1 )
  3557. {
  3558. // If the value is larger than the largest case value in the range, jump to the next range
  3559. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3560. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3561. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3562. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3563. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3564. }
  3565. // Jump forward according to the value
  3566. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3567. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3568. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3569. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3570. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3571. // Add the list of jumps to the correct labels (any holes, jump to default)
  3572. index = ranges[range];
  3573. for( int i = caseValues[index]; i <= maxRange; i++ )
  3574. {
  3575. if( caseValues[index] == i )
  3576. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3577. else
  3578. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3579. }
  3580. expr.bc.Label((short)nextRangeLabel);
  3581. }
  3582. else
  3583. {
  3584. // Simply make a comparison with each value
  3585. for( int i = ranges[range]; i < index; ++i )
  3586. {
  3587. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3588. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3589. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3590. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3591. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3592. }
  3593. }
  3594. }
  3595. // Catch any value that falls trough
  3596. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3597. // Release the temporary variable previously stored
  3598. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3599. // TODO: optimize: Should optimize each piece individually
  3600. expr.bc.OptimizeLocally(tempVariableOffsets);
  3601. //----------------------------------
  3602. // Output case implementations
  3603. //----------------------------------
  3604. // Compile case implementations, each one with the label before it
  3605. cnode = snode->firstChild->next;
  3606. while( cnode )
  3607. {
  3608. // Each case should have a constant expression
  3609. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3610. {
  3611. expr.bc.Label((short)firstCaseLabel++);
  3612. CompileCase(cnode->firstChild->next, &expr.bc);
  3613. }
  3614. else
  3615. {
  3616. expr.bc.Label((short)defaultLabel);
  3617. // Is default the last case?
  3618. if( cnode->next )
  3619. {
  3620. // We've already reported this error
  3621. break;
  3622. }
  3623. CompileCase(cnode->firstChild, &expr.bc);
  3624. }
  3625. cnode = cnode->next;
  3626. }
  3627. //--------------------------------
  3628. bc->AddCode(&expr.bc);
  3629. // Add break label
  3630. bc->Label((short)breakLabel);
  3631. breakLabels.PopLast();
  3632. RemoveVariableScope();
  3633. }
  3634. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3635. {
  3636. bool isFinished = false;
  3637. bool hasReturn = false;
  3638. bool hasUnreachableCode = false;
  3639. while( node )
  3640. {
  3641. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3642. {
  3643. hasUnreachableCode = true;
  3644. Warning(TXT_UNREACHABLE_CODE, node);
  3645. break;
  3646. }
  3647. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3648. isFinished = true;
  3649. asCByteCode statement(engine);
  3650. if( node->nodeType == snDeclaration )
  3651. {
  3652. Error(TXT_DECL_IN_SWITCH, node);
  3653. // Compile it anyway to avoid further compiler errors
  3654. CompileDeclaration(node, &statement);
  3655. }
  3656. else
  3657. CompileStatement(node, &hasReturn, &statement);
  3658. LineInstr(bc, node->tokenPos);
  3659. bc->AddCode(&statement);
  3660. if( !hasCompileErrors )
  3661. asASSERT( tempVariables.GetLength() == 0 );
  3662. node = node->next;
  3663. }
  3664. }
  3665. void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc)
  3666. {
  3667. // We will use one label before and another after the catch statement
  3668. int beforeCatchLabel = nextLabel++;
  3669. int afterCatchLabel = nextLabel++;
  3670. // Compile the try block
  3671. bool hasReturnTry;
  3672. asCByteCode tryBC(engine);
  3673. CompileStatement(node->firstChild, &hasReturnTry, &tryBC);
  3674. // Add marker to unwind exception until here, then jump to catch block
  3675. bc->TryBlock((short)beforeCatchLabel);
  3676. // Add the byte code
  3677. LineInstr(bc, node->firstChild->tokenPos);
  3678. bc->AddCode(&tryBC);
  3679. // Add jump to after catch
  3680. bc->InstrINT(asBC_JMP, afterCatchLabel);
  3681. // Compile the catch block
  3682. bool hasReturnCatch;
  3683. asCByteCode catchBC(engine);
  3684. CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC);
  3685. // Add marker to tell bytecode optimizer that this is a catch
  3686. // block so the code is not removed as unreachable code
  3687. bc->Label((short)beforeCatchLabel);
  3688. // Add the byte code
  3689. LineInstr(bc, node->firstChild->next->tokenPos);
  3690. bc->AddCode(&catchBC);
  3691. // Add the label after catch
  3692. bc->Label((short)afterCatchLabel);
  3693. // The try/catch statement only has return (i.e. no code after
  3694. // the try/catch block will be executed) if both blocks have
  3695. *hasReturn = hasReturnTry && hasReturnCatch;
  3696. }
  3697. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3698. {
  3699. // We will use one label for the if statement
  3700. // and possibly another for the else statement
  3701. int afterLabel = nextLabel++;
  3702. // Compile the expression
  3703. asCExprContext expr(engine);
  3704. int r = CompileAssignment(inode->firstChild, &expr);
  3705. if( r == 0 )
  3706. {
  3707. // Allow value types to be converted to bool using 'bool opImplConv()'
  3708. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3709. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3710. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3711. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3712. else
  3713. {
  3714. if( !expr.type.isConstant )
  3715. {
  3716. if( ProcessPropertyGetAccessor(&expr, inode) < 0 )
  3717. return;
  3718. ConvertToVariable(&expr);
  3719. ProcessDeferredParams(&expr);
  3720. // Add a test
  3721. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3722. expr.bc.Instr(asBC_ClrHi);
  3723. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3724. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3725. expr.bc.OptimizeLocally(tempVariableOffsets);
  3726. bc->AddCode(&expr.bc);
  3727. }
  3728. #if AS_SIZEOF_BOOL == 1
  3729. else if( expr.type.GetConstantB() == 0 )
  3730. #else
  3731. else if (expr.type.GetConstantDW() == 0)
  3732. #endif
  3733. {
  3734. // Jump to the else case
  3735. bc->InstrINT(asBC_JMP, afterLabel);
  3736. // TODO: Should we warn that the expression will always go to the else?
  3737. }
  3738. }
  3739. }
  3740. // Compile the if statement
  3741. bool origIsConstructorCalled = m_isConstructorCalled;
  3742. bool hasReturn1;
  3743. asCByteCode ifBC(engine);
  3744. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3745. // Add the byte code
  3746. LineInstr(bc, inode->firstChild->next->tokenPos);
  3747. bc->AddCode(&ifBC);
  3748. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3749. {
  3750. // Don't allow if( expr );
  3751. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3752. }
  3753. // If one of the statements call the constructor, the other must as well
  3754. // otherwise it is possible the constructor is never called
  3755. bool constructorCall1 = false;
  3756. bool constructorCall2 = false;
  3757. if( !origIsConstructorCalled && m_isConstructorCalled )
  3758. constructorCall1 = true;
  3759. // Do we have an else statement?
  3760. if( inode->firstChild->next != inode->lastChild )
  3761. {
  3762. // Reset the constructor called flag so the else statement can call the constructor too
  3763. m_isConstructorCalled = origIsConstructorCalled;
  3764. int afterElse = 0;
  3765. if( !hasReturn1 )
  3766. {
  3767. afterElse = nextLabel++;
  3768. // Add jump to after the else statement
  3769. bc->InstrINT(asBC_JMP, afterElse);
  3770. }
  3771. // Add label for the else statement
  3772. bc->Label((short)afterLabel);
  3773. bool hasReturn2;
  3774. asCByteCode elseBC(engine);
  3775. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3776. // Add byte code for the else statement
  3777. LineInstr(bc, inode->lastChild->tokenPos);
  3778. bc->AddCode(&elseBC);
  3779. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3780. {
  3781. // Don't allow if( expr ) {} else;
  3782. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3783. }
  3784. if( !hasReturn1 )
  3785. {
  3786. // Add label for the end of else statement
  3787. bc->Label((short)afterElse);
  3788. }
  3789. // The if statement only has return if both alternatives have
  3790. *hasReturn = hasReturn1 && hasReturn2;
  3791. if( !origIsConstructorCalled && m_isConstructorCalled )
  3792. constructorCall2 = true;
  3793. }
  3794. else
  3795. {
  3796. // Add label for the end of if statement
  3797. bc->Label((short)afterLabel);
  3798. *hasReturn = false;
  3799. }
  3800. // Make sure both or neither conditions call a constructor
  3801. if( (constructorCall1 && !constructorCall2) ||
  3802. (constructorCall2 && !constructorCall1) )
  3803. {
  3804. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3805. }
  3806. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3807. }
  3808. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3809. {
  3810. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3811. AddVariableScope(true, true);
  3812. // We will use three labels for the for loop
  3813. int conditionLabel = nextLabel++;
  3814. int afterLabel = nextLabel++;
  3815. int continueLabel = nextLabel++;
  3816. int insideLabel = nextLabel++;
  3817. continueLabels.PushLast(continueLabel);
  3818. breakLabels.PushLast(afterLabel);
  3819. //---------------------------------------
  3820. // Compile the initialization statement
  3821. asCByteCode initBC(engine);
  3822. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3823. if( fnode->firstChild->nodeType == snDeclaration )
  3824. CompileDeclaration(fnode->firstChild, &initBC);
  3825. else
  3826. CompileExpressionStatement(fnode->firstChild, &initBC);
  3827. //-----------------------------------
  3828. // Compile the condition statement
  3829. asCExprContext expr(engine);
  3830. asCScriptNode *second = fnode->firstChild->next;
  3831. if( second->firstChild )
  3832. {
  3833. int r = CompileAssignment(second->firstChild, &expr);
  3834. if( r >= 0 )
  3835. {
  3836. // Allow value types to be converted to bool using 'bool opImplConv()'
  3837. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3838. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3839. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3840. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3841. else
  3842. {
  3843. if( ProcessPropertyGetAccessor(&expr, second) < 0 )
  3844. return;
  3845. ConvertToVariable(&expr);
  3846. ProcessDeferredParams(&expr);
  3847. // If expression is false exit the loop
  3848. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3849. expr.bc.Instr(asBC_ClrHi);
  3850. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3851. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3852. expr.bc.OptimizeLocally(tempVariableOffsets);
  3853. // Prepend the line instruction for the condition
  3854. asCByteCode tmp(engine);
  3855. LineInstr(&tmp, second->firstChild->tokenPos);
  3856. tmp.AddCode(&expr.bc);
  3857. expr.bc.AddCode(&tmp);
  3858. }
  3859. }
  3860. }
  3861. //---------------------------
  3862. // Compile the increment statement(s)
  3863. asCByteCode nextBC(engine);
  3864. asCScriptNode *cnode = second->next;
  3865. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3866. {
  3867. LineInstr(&nextBC, cnode->tokenPos);
  3868. CompileExpressionStatement(cnode, &nextBC);
  3869. cnode = cnode->next;
  3870. }
  3871. //------------------------------
  3872. // Compile loop statement
  3873. bool hasReturn;
  3874. asCByteCode forBC(engine);
  3875. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3876. //-------------------------------
  3877. // Join the code pieces
  3878. bc->AddCode(&initBC);
  3879. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3880. bc->Label((short)insideLabel);
  3881. // Add a suspend bytecode inside the loop to guarantee
  3882. // that the application can suspend the execution
  3883. bc->Instr(asBC_SUSPEND);
  3884. bc->InstrPTR(asBC_JitEntry, 0);
  3885. LineInstr(bc, fnode->lastChild->tokenPos);
  3886. bc->AddCode(&forBC);
  3887. bc->Label((short)continueLabel);
  3888. bc->AddCode(&nextBC);
  3889. bc->Label((short)conditionLabel);
  3890. if( expr.bc.GetLastInstr() == -1 )
  3891. // There is no condition, so we just always jump
  3892. bc->InstrDWORD(asBC_JMP, insideLabel);
  3893. else
  3894. bc->AddCode(&expr.bc);
  3895. bc->Label((short)afterLabel);
  3896. continueLabels.PopLast();
  3897. breakLabels.PopLast();
  3898. // Deallocate variables in this block, in reverse order
  3899. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3900. {
  3901. sVariable *v = variables->variables[n];
  3902. // Call variable destructors here, for variables not yet destroyed
  3903. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3904. // Don't deallocate function parameters
  3905. if( v->stackOffset > 0 )
  3906. DeallocateVariable(v->stackOffset);
  3907. }
  3908. RemoveVariableScope();
  3909. }
  3910. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3911. {
  3912. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3913. AddVariableScope(true, true);
  3914. // We will use two labels for the while loop
  3915. int beforeLabel = nextLabel++;
  3916. int afterLabel = nextLabel++;
  3917. continueLabels.PushLast(beforeLabel);
  3918. breakLabels.PushLast(afterLabel);
  3919. // Add label before the expression
  3920. bc->Label((short)beforeLabel);
  3921. // Compile expression
  3922. asCExprContext expr(engine);
  3923. int r = CompileAssignment(wnode->firstChild, &expr);
  3924. if( r == 0 )
  3925. {
  3926. // Allow value types to be converted to bool using 'bool opImplConv()'
  3927. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3928. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3929. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3930. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3931. else
  3932. {
  3933. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  3934. return;
  3935. ConvertToVariable(&expr);
  3936. ProcessDeferredParams(&expr);
  3937. // Jump to end of statement if expression is false
  3938. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3939. expr.bc.Instr(asBC_ClrHi);
  3940. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3941. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3942. expr.bc.OptimizeLocally(tempVariableOffsets);
  3943. bc->AddCode(&expr.bc);
  3944. }
  3945. }
  3946. // Add a suspend bytecode inside the loop to guarantee
  3947. // that the application can suspend the execution
  3948. bc->Instr(asBC_SUSPEND);
  3949. bc->InstrPTR(asBC_JitEntry, 0);
  3950. // Compile statement
  3951. bool hasReturn;
  3952. asCByteCode whileBC(engine);
  3953. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3954. // Add byte code for the statement
  3955. LineInstr(bc, wnode->lastChild->tokenPos);
  3956. bc->AddCode(&whileBC);
  3957. // Jump to the expression
  3958. bc->InstrINT(asBC_JMP, beforeLabel);
  3959. // Add label after the statement
  3960. bc->Label((short)afterLabel);
  3961. continueLabels.PopLast();
  3962. breakLabels.PopLast();
  3963. RemoveVariableScope();
  3964. }
  3965. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3966. {
  3967. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3968. AddVariableScope(true, true);
  3969. // We will use two labels for the while loop
  3970. int beforeLabel = nextLabel++;
  3971. int beforeTest = nextLabel++;
  3972. int afterLabel = nextLabel++;
  3973. continueLabels.PushLast(beforeTest);
  3974. breakLabels.PushLast(afterLabel);
  3975. // Add label before the statement
  3976. bc->Label((short)beforeLabel);
  3977. // Compile statement
  3978. bool hasReturn;
  3979. asCByteCode whileBC(engine);
  3980. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3981. // Add byte code for the statement
  3982. LineInstr(bc, wnode->firstChild->tokenPos);
  3983. bc->AddCode(&whileBC);
  3984. // Add label before the expression
  3985. bc->Label((short)beforeTest);
  3986. // Add a suspend bytecode inside the loop to guarantee
  3987. // that the application can suspend the execution
  3988. bc->Instr(asBC_SUSPEND);
  3989. bc->InstrPTR(asBC_JitEntry, 0);
  3990. // Add a line instruction
  3991. LineInstr(bc, wnode->lastChild->tokenPos);
  3992. // Compile expression
  3993. asCExprContext expr(engine);
  3994. CompileAssignment(wnode->lastChild, &expr);
  3995. // Allow value types to be converted to bool using 'bool opImplConv()'
  3996. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3997. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  3998. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3999. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  4000. else
  4001. {
  4002. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  4003. return;
  4004. ConvertToVariable(&expr);
  4005. ProcessDeferredParams(&expr);
  4006. // Jump to next iteration if expression is true
  4007. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4008. expr.bc.Instr(asBC_ClrHi);
  4009. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  4010. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4011. expr.bc.OptimizeLocally(tempVariableOffsets);
  4012. bc->AddCode(&expr.bc);
  4013. }
  4014. // Add label after the statement
  4015. bc->Label((short)afterLabel);
  4016. continueLabels.PopLast();
  4017. breakLabels.PopLast();
  4018. RemoveVariableScope();
  4019. }
  4020. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  4021. {
  4022. if( breakLabels.GetLength() == 0 )
  4023. {
  4024. Error(TXT_INVALID_BREAK, node);
  4025. return;
  4026. }
  4027. // Add destructor calls for all variables that will go out of scope
  4028. // Put this clean up in a block to allow exception handler to understand them
  4029. bc->Block(true);
  4030. asCVariableScope *vs = variables;
  4031. while( !vs->isBreakScope )
  4032. {
  4033. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4034. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4035. vs = vs->parent;
  4036. }
  4037. bc->Block(false);
  4038. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  4039. }
  4040. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  4041. {
  4042. if( continueLabels.GetLength() == 0 )
  4043. {
  4044. Error(TXT_INVALID_CONTINUE, node);
  4045. return;
  4046. }
  4047. // Add destructor calls for all variables that will go out of scope
  4048. // Put this clean up in a block to allow exception handler to understand them
  4049. bc->Block(true);
  4050. asCVariableScope *vs = variables;
  4051. while( !vs->isContinueScope )
  4052. {
  4053. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4054. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4055. vs = vs->parent;
  4056. }
  4057. bc->Block(false);
  4058. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  4059. }
  4060. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  4061. {
  4062. if( enode->firstChild )
  4063. {
  4064. // Compile the expression
  4065. asCExprContext expr(engine);
  4066. CompileAssignment(enode->firstChild, &expr);
  4067. // Must not have unused ambiguous names
  4068. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  4069. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  4070. // Must not have unused anonymous functions
  4071. if( expr.IsLambda() )
  4072. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  4073. // If we get here and there is still an unprocessed property
  4074. // accessor, then process it as a get access. Don't call if there is
  4075. // already a compile error, or we might report an error that is not valid
  4076. if( !hasCompileErrors )
  4077. if( ProcessPropertyGetAccessor(&expr, enode) < 0 )
  4078. return;
  4079. // Pop the value from the stack
  4080. if( !expr.type.dataType.IsPrimitive() )
  4081. expr.bc.Instr(asBC_PopPtr);
  4082. // Release temporary variables used by expression
  4083. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4084. ProcessDeferredParams(&expr);
  4085. expr.bc.OptimizeLocally(tempVariableOffsets);
  4086. bc->AddCode(&expr.bc);
  4087. }
  4088. }
  4089. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  4090. {
  4091. // The input can be either an object or funcdef, either as handle or reference
  4092. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  4093. // If the object already is stored in temporary variable then nothing needs to be done
  4094. // Note, a type can be temporary without being a variable, in which case it is holding off
  4095. // on releasing a previously used object.
  4096. if( ctx->type.isTemporary && ctx->type.isVariable &&
  4097. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  4098. {
  4099. // If the temporary object is currently not a reference
  4100. // the expression needs to be reevaluated to a reference
  4101. if( !ctx->type.dataType.IsReference() )
  4102. {
  4103. ctx->bc.Instr(asBC_PopPtr);
  4104. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4105. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4106. }
  4107. return;
  4108. }
  4109. // Allocate temporary variable
  4110. asCDataType dt = ctx->type.dataType;
  4111. dt.MakeReference(false);
  4112. dt.MakeReadOnly(false);
  4113. int offset = AllocateVariable(dt, true, forceOnHeap);
  4114. // Objects stored on the stack are not considered references
  4115. dt.MakeReference(IsVariableOnHeap(offset));
  4116. asCExprValue lvalue;
  4117. lvalue.Set(dt);
  4118. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  4119. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4120. bool prevIsTemp = ctx->type.isTemporary;
  4121. int prevStackOffset = ctx->type.stackOffset;
  4122. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  4123. // Release the previous temporary variable if it hasn't already been released
  4124. if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
  4125. ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
  4126. // Push the reference to the temporary variable on the stack
  4127. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4128. ctx->type.Set(dt);
  4129. ctx->type.isTemporary = true;
  4130. ctx->type.stackOffset = (short)offset;
  4131. ctx->type.isVariable = true;
  4132. ctx->type.isExplicitHandle = isExplicitHandle;
  4133. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4134. }
  4135. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  4136. {
  4137. // Get return type and location
  4138. sVariable *v = variables->GetVariable("return");
  4139. // Basic validations
  4140. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  4141. {
  4142. Error(TXT_MUST_RETURN_VALUE, rnode);
  4143. return;
  4144. }
  4145. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  4146. {
  4147. Error(TXT_CANT_RETURN_VALUE, rnode);
  4148. return;
  4149. }
  4150. // Compile the expression
  4151. if( rnode->firstChild )
  4152. {
  4153. // Compile the expression
  4154. asCExprContext expr(engine);
  4155. int r = CompileAssignment(rnode->firstChild, &expr);
  4156. if( r < 0 ) return;
  4157. if( v->type.IsReference() )
  4158. {
  4159. // The expression that gives the reference must not use any of the
  4160. // variables that must be destroyed upon exit, because then it means
  4161. // reference will stay alive while the clean-up is done, which could
  4162. // potentially mean that the reference is invalidated by the clean-up.
  4163. //
  4164. // When the function is returning a reference, the clean-up of the
  4165. // variables must be done before the evaluation of the expression.
  4166. //
  4167. // A reference to a global variable, or a class member for class methods
  4168. // should be allowed to be returned.
  4169. if( !(expr.type.dataType.IsReference() ||
  4170. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  4171. {
  4172. // Clean up the potential deferred parameters
  4173. ProcessDeferredParams(&expr);
  4174. Error(TXT_NOT_VALID_REFERENCE, rnode);
  4175. return;
  4176. }
  4177. // No references to local variables, temporary variables, or parameters
  4178. // are allowed to be returned, since they go out of scope when the function
  4179. // returns. Even reference parameters are disallowed, since it is not possible
  4180. // to know the scope of them. The exception is the 'this' pointer, which
  4181. // is treated by the compiler as a local variable, but isn't really so.
  4182. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  4183. {
  4184. // Clean up the potential deferred parameters
  4185. ProcessDeferredParams(&expr);
  4186. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  4187. return;
  4188. }
  4189. // The type must match exactly as we cannot convert
  4190. // the reference without loosing the original value
  4191. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  4192. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  4193. !expr.type.dataType.IsObjectHandle() &&
  4194. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  4195. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4196. {
  4197. // Clean up the potential deferred parameters
  4198. ProcessDeferredParams(&expr);
  4199. asCString str;
  4200. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4201. Error(str, rnode);
  4202. return;
  4203. }
  4204. // The expression must not have any deferred expressions, because the evaluation
  4205. // of these cannot be done without keeping the reference which is not safe
  4206. if( expr.deferredParams.GetLength() )
  4207. {
  4208. // Clean up the potential deferred parameters
  4209. ProcessDeferredParams(&expr);
  4210. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4211. return;
  4212. }
  4213. // Make sure the expression isn't using any local variables that
  4214. // will need to be cleaned up before the function completes
  4215. asCArray<int> usedVars;
  4216. expr.bc.GetVarsUsed(usedVars);
  4217. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4218. {
  4219. int var = GetVariableSlot(usedVars[n]);
  4220. if( var != -1 )
  4221. {
  4222. asCDataType dt = variableAllocations[var];
  4223. if( dt.IsObject() )
  4224. {
  4225. ProcessDeferredParams(&expr);
  4226. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4227. return;
  4228. }
  4229. }
  4230. }
  4231. // Can't return the reference if could point to a local variable
  4232. if( expr.type.isRefToLocal )
  4233. {
  4234. ProcessDeferredParams(&expr);
  4235. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4236. return;
  4237. }
  4238. // All objects in the function must be cleaned up before the expression
  4239. // is evaluated, otherwise there is a possibility that the cleanup will
  4240. // invalidate the reference.
  4241. // Destroy the local variables before loading
  4242. // the reference into the register. This will
  4243. // be done before the expression is evaluated.
  4244. DestroyVariables(bc);
  4245. // For primitives the reference is already in the register,
  4246. // but for non-primitives the reference is on the stack so we
  4247. // need to load it into the register
  4248. if( !expr.type.dataType.IsPrimitive() )
  4249. {
  4250. if( !expr.type.dataType.IsObjectHandle() &&
  4251. expr.type.dataType.IsReference() )
  4252. expr.bc.Instr(asBC_RDSPtr);
  4253. expr.bc.Instr(asBC_PopRPtr);
  4254. }
  4255. // There are no temporaries to release so we're done
  4256. }
  4257. else // if( !v->type.IsReference() )
  4258. {
  4259. if( ProcessPropertyGetAccessor(&expr, rnode) < 0 )
  4260. return;
  4261. // Prepare the value for assignment
  4262. IsVariableInitialized(&expr.type, rnode->firstChild);
  4263. if( v->type.IsPrimitive() )
  4264. {
  4265. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4266. // Implicitly convert the value to the return type
  4267. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4268. // Verify that the conversion was successful
  4269. if( expr.type.dataType != v->type )
  4270. {
  4271. asCString str;
  4272. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4273. Error(str, rnode);
  4274. return;
  4275. }
  4276. else
  4277. {
  4278. ConvertToVariable(&expr);
  4279. // Clean up the local variables and process deferred parameters
  4280. DestroyVariables(&expr.bc);
  4281. ProcessDeferredParams(&expr);
  4282. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4283. // Load the variable in the register
  4284. if( v->type.GetSizeOnStackDWords() == 1 )
  4285. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4286. else
  4287. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4288. }
  4289. }
  4290. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4291. {
  4292. // Value types are returned on the stack, in a location
  4293. // that has been reserved by the calling function.
  4294. if( outFunc->DoesReturnOnStack() )
  4295. {
  4296. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4297. // it should be called directly instead of first converting the expression and
  4298. // then copy the value.
  4299. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4300. {
  4301. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4302. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4303. {
  4304. asCString str;
  4305. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4306. Error(str, rnode->firstChild);
  4307. return;
  4308. }
  4309. }
  4310. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4311. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4312. // Clean up the local variables and process deferred parameters
  4313. DestroyVariables(&expr.bc);
  4314. ProcessDeferredParams(&expr);
  4315. }
  4316. else
  4317. {
  4318. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4319. // Prepare the expression to be loaded into the object
  4320. // register. This will place the reference in local variable
  4321. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4322. // Pop the reference to the temporary variable
  4323. expr.bc.Instr(asBC_PopPtr);
  4324. // Clean up the local variables and process deferred parameters
  4325. DestroyVariables(&expr.bc);
  4326. ProcessDeferredParams(&expr);
  4327. // Load the object pointer into the object register
  4328. // LOADOBJ also clears the address in the variable
  4329. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4330. // LOADOBJ cleared the address in the variable so the object will not be freed
  4331. // here, but the temporary variable must still be freed so the slot can be reused
  4332. // By releasing without the bytecode we do just that.
  4333. ReleaseTemporaryVariable(expr.type, 0);
  4334. }
  4335. }
  4336. }
  4337. expr.bc.OptimizeLocally(tempVariableOffsets);
  4338. bc->AddCode(&expr.bc);
  4339. }
  4340. else
  4341. {
  4342. // For functions that don't return anything
  4343. // we just detroy the local variables
  4344. DestroyVariables(bc);
  4345. }
  4346. // Jump to the end of the function
  4347. bc->InstrINT(asBC_JMP, 0);
  4348. }
  4349. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4350. {
  4351. // Call destructor on all variables except for the function parameters
  4352. // Put the clean-up in a block to allow exception handler to understand this
  4353. bc->Block(true);
  4354. asCVariableScope *vs = variables;
  4355. while( vs )
  4356. {
  4357. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4358. if( vs->variables[n]->stackOffset > 0 )
  4359. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4360. vs = vs->parent;
  4361. }
  4362. bc->Block(false);
  4363. }
  4364. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4365. {
  4366. variables = asNEW(asCVariableScope)(variables);
  4367. if( variables == 0 )
  4368. {
  4369. // Out of memory
  4370. return;
  4371. }
  4372. variables->isBreakScope = isBreakScope;
  4373. variables->isContinueScope = isContinueScope;
  4374. }
  4375. void asCCompiler::RemoveVariableScope()
  4376. {
  4377. if( variables )
  4378. {
  4379. asCVariableScope *var = variables;
  4380. variables = variables->parent;
  4381. asDELETE(var,asCVariableScope);
  4382. }
  4383. }
  4384. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4385. {
  4386. asCString str;
  4387. int r = 0, c = 0;
  4388. asASSERT( node );
  4389. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4390. builder->WriteError(script->name, msg, r, c);
  4391. hasCompileErrors = true;
  4392. }
  4393. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4394. {
  4395. asCString str;
  4396. int r = 0, c = 0;
  4397. asASSERT( node );
  4398. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4399. builder->WriteWarning(script->name, msg, r, c);
  4400. }
  4401. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4402. {
  4403. asCString str;
  4404. int r = 0, c = 0;
  4405. asASSERT( node );
  4406. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4407. builder->WriteInfo(script->name, msg, r, c, false);
  4408. }
  4409. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4410. {
  4411. int r = 0, c = 0;
  4412. asASSERT( node );
  4413. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4414. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4415. {
  4416. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4417. if( inType && func->funcType == asFUNC_VIRTUAL )
  4418. func = inType->virtualFunctionTable[func->vfTableIdx];
  4419. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4420. if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE))
  4421. {
  4422. // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user
  4423. for (unsigned int p = 0; p < func->GetParamCount(); p++)
  4424. {
  4425. int typeId = 0;
  4426. func->GetParam(p, &typeId);
  4427. asITypeInfo *ti = engine->GetTypeInfoById(typeId);
  4428. if (ti && (ti->GetFlags() & asOBJ_FUNCDEF))
  4429. {
  4430. asCString msg;
  4431. msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration());
  4432. builder->WriteInfo(script->name, msg.AddressOf(), r, c, false);
  4433. }
  4434. }
  4435. }
  4436. }
  4437. }
  4438. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4439. {
  4440. int l = int(reservedVariables.GetLength());
  4441. ctx->bc.GetVarsUsed(reservedVariables);
  4442. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4443. reservedVariables.SetLength(l);
  4444. return var;
  4445. }
  4446. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference)
  4447. {
  4448. asCDataType t(type);
  4449. t.MakeReference(asReference);
  4450. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4451. t.SetTokenType(ttInt);
  4452. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4453. t.SetTokenType(ttDouble);
  4454. // Only null handles have the token type unrecognized token
  4455. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4456. bool isOnHeap = true;
  4457. if( t.IsPrimitive() ||
  4458. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap && !asReference) )
  4459. {
  4460. // Primitives and value types (unless overridden) are allocated on the stack
  4461. isOnHeap = false;
  4462. }
  4463. // Find a free location with the same type
  4464. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4465. {
  4466. int slot = freeVariables[n];
  4467. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4468. variableIsTemporary[slot] == isTemporary &&
  4469. variableIsOnHeap[slot] == isOnHeap )
  4470. {
  4471. // We can't return by slot, must count variable sizes
  4472. int offset = GetVariableOffset(slot);
  4473. // Verify that it is not in the list of reserved variables
  4474. bool isUsed = false;
  4475. if( reservedVariables.GetLength() )
  4476. isUsed = reservedVariables.Exists(offset);
  4477. if( !isUsed )
  4478. {
  4479. if( n != freeVariables.GetLength() - 1 )
  4480. freeVariables[n] = freeVariables.PopLast();
  4481. else
  4482. freeVariables.PopLast();
  4483. if( isTemporary )
  4484. tempVariables.PushLast(offset);
  4485. return offset;
  4486. }
  4487. }
  4488. }
  4489. variableAllocations.PushLast(t);
  4490. variableIsTemporary.PushLast(isTemporary);
  4491. variableIsOnHeap.PushLast(isOnHeap);
  4492. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4493. if( isTemporary )
  4494. {
  4495. // Add offset to the currently allocated temporary variables
  4496. tempVariables.PushLast(offset);
  4497. // Add offset to all known offsets to temporary variables, whether allocated or not
  4498. tempVariableOffsets.PushLast(offset);
  4499. }
  4500. return offset;
  4501. }
  4502. int asCCompiler::GetVariableOffset(int varIndex)
  4503. {
  4504. // Return offset to the last dword on the stack
  4505. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4506. int varOffset = 1;
  4507. // Skip lower variables
  4508. for( int n = 0; n < varIndex; n++ )
  4509. {
  4510. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4511. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4512. else
  4513. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4514. }
  4515. if( varIndex < (int)variableAllocations.GetLength() )
  4516. {
  4517. // For variables larger than 1 dword the returned offset should be to the last dword
  4518. int size;
  4519. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4520. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4521. else
  4522. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4523. if( size > 1 )
  4524. varOffset += size-1;
  4525. }
  4526. return varOffset;
  4527. }
  4528. int asCCompiler::GetVariableSlot(int offset)
  4529. {
  4530. int varOffset = 1;
  4531. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4532. {
  4533. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4534. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4535. else
  4536. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4537. if( varOffset == offset )
  4538. return n;
  4539. varOffset++;
  4540. }
  4541. return -1;
  4542. }
  4543. bool asCCompiler::IsVariableOnHeap(int offset)
  4544. {
  4545. int varSlot = GetVariableSlot(offset);
  4546. if( varSlot < 0 )
  4547. {
  4548. // This happens for function arguments that are considered as on the heap
  4549. return true;
  4550. }
  4551. return variableIsOnHeap[varSlot];
  4552. }
  4553. void asCCompiler::DeallocateVariable(int offset)
  4554. {
  4555. // Remove temporary variable
  4556. int n;
  4557. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4558. {
  4559. if( offset == tempVariables[n] )
  4560. {
  4561. if( n == (int)tempVariables.GetLength()-1 )
  4562. tempVariables.PopLast();
  4563. else
  4564. tempVariables[n] = tempVariables.PopLast();
  4565. break;
  4566. }
  4567. }
  4568. // Mark the variable slot available for new allocations
  4569. n = GetVariableSlot(offset);
  4570. if( n != -1 )
  4571. {
  4572. freeVariables.PushLast(n);
  4573. return;
  4574. }
  4575. // We might get here if the variable was implicitly declared
  4576. // because it was used before a formal declaration, in this case
  4577. // the offset is 0x7FFF
  4578. asASSERT(offset == 0x7FFF);
  4579. }
  4580. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4581. {
  4582. if( t.isTemporary )
  4583. {
  4584. ReleaseTemporaryVariable(t.stackOffset, bc);
  4585. t.isTemporary = false;
  4586. }
  4587. }
  4588. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4589. {
  4590. asASSERT( tempVariables.Exists(offset) );
  4591. if( bc )
  4592. {
  4593. // We need to call the destructor on the true variable type
  4594. int n = GetVariableSlot(offset);
  4595. asASSERT( n >= 0 );
  4596. if( n >= 0 )
  4597. {
  4598. asCDataType dt = variableAllocations[n];
  4599. bool isOnHeap = variableIsOnHeap[n];
  4600. // Call destructor
  4601. CallDestructor(dt, offset, isOnHeap, bc);
  4602. }
  4603. }
  4604. DeallocateVariable(offset);
  4605. }
  4606. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4607. {
  4608. if( ctx->type.dataType.IsReference() )
  4609. {
  4610. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4611. {
  4612. ctx->type.dataType.MakeReference(false);
  4613. if( generateCode )
  4614. ctx->bc.Instr(asBC_RDSPtr);
  4615. }
  4616. else
  4617. {
  4618. // This should never happen as primitives are treated differently
  4619. asASSERT(false);
  4620. }
  4621. }
  4622. }
  4623. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4624. {
  4625. // No need to check if there is no variable scope
  4626. if( variables == 0 ) return true;
  4627. // Temporary variables are assumed to be initialized
  4628. if( type->isTemporary ) return true;
  4629. // Verify that it is a variable
  4630. if( !type->isVariable ) return true;
  4631. // Find the variable
  4632. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4633. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4634. if( v == 0 ) return true;
  4635. if( v->isInitialized ) return true;
  4636. // Complex types don't need this test
  4637. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4638. // Mark as initialized so that the user will not be bothered again
  4639. v->isInitialized = true;
  4640. // Write warning
  4641. asCString str;
  4642. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4643. Warning(str, node);
  4644. return false;
  4645. }
  4646. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4647. {
  4648. // Check if the variable is initialized (if it indeed is a variable)
  4649. IsVariableInitialized(&ctx->type, node);
  4650. asCDataType to = ctx->type.dataType;
  4651. to.MakeReference(false);
  4652. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4653. ProcessDeferredParams(ctx);
  4654. }
  4655. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4656. {
  4657. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4658. int l = int(reservedVariables.GetLength());
  4659. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4660. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  4661. return;
  4662. // Make sure the rvalue is initialized if it is a variable
  4663. IsVariableInitialized(&rctx->type, node);
  4664. if( lvalue->IsPrimitive() )
  4665. {
  4666. if( rctx->type.dataType.IsPrimitive() )
  4667. {
  4668. if( rctx->type.dataType.IsReference() )
  4669. {
  4670. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4671. ConvertToVariableNotIn(rctx, lvalueExpr);
  4672. }
  4673. }
  4674. // Implicitly convert the value to the right type
  4675. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4676. // Check data type
  4677. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4678. {
  4679. asCString str;
  4680. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4681. Error(str, node);
  4682. rctx->type.SetDummy();
  4683. }
  4684. // Make sure the rvalue is a variable
  4685. if( !rctx->type.isVariable )
  4686. ConvertToVariableNotIn(rctx, lvalueExpr);
  4687. }
  4688. else
  4689. {
  4690. asCDataType to = *lvalue;
  4691. to.MakeReference(false);
  4692. // TODO: ImplicitConversion should know to do this by itself
  4693. // First convert to a handle which will do a reference cast
  4694. if( !lvalue->IsObjectHandle() &&
  4695. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4696. to.MakeHandle(true);
  4697. // Don't allow the implicit conversion to create an object
  4698. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4699. if( !lvalue->IsObjectHandle() &&
  4700. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4701. {
  4702. // Then convert to a reference, which will validate the handle
  4703. to.MakeHandle(false);
  4704. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4705. }
  4706. // Check data type
  4707. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4708. {
  4709. asCString str;
  4710. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4711. Error(str, node);
  4712. }
  4713. else
  4714. {
  4715. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4716. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4717. }
  4718. }
  4719. // Unreserve variables
  4720. reservedVariables.SetLength(l);
  4721. }
  4722. bool asCCompiler::IsLValue(asCExprValue &type)
  4723. {
  4724. if( !type.isLValue ) return false;
  4725. if( type.dataType.IsReadOnly() ) return false;
  4726. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4727. return true;
  4728. }
  4729. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4730. {
  4731. if( lvalue->dataType.IsReadOnly() )
  4732. {
  4733. Error(TXT_REF_IS_READ_ONLY, node);
  4734. return -1;
  4735. }
  4736. if( lvalue->dataType.IsPrimitive() )
  4737. {
  4738. if( lvalue->isVariable )
  4739. {
  4740. // Copy the value between the variables directly
  4741. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4742. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4743. else
  4744. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4745. // Mark variable as initialized
  4746. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4747. if( v ) v->isInitialized = true;
  4748. }
  4749. else if( lvalue->dataType.IsReference() )
  4750. {
  4751. // Copy the value of the variable to the reference in the register
  4752. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4753. if( s == 1 )
  4754. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4755. else if( s == 2 )
  4756. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4757. else if( s == 4 )
  4758. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4759. else if( s == 8 )
  4760. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4761. }
  4762. else
  4763. {
  4764. Error(TXT_NOT_VALID_LVALUE, node);
  4765. return -1;
  4766. }
  4767. }
  4768. else if( !lvalue->isExplicitHandle )
  4769. {
  4770. asCExprContext ctx(engine);
  4771. ctx.type = *lvalue;
  4772. Dereference(&ctx, true);
  4773. *lvalue = ctx.type;
  4774. bc->AddCode(&ctx.bc);
  4775. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4776. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4777. {
  4778. asCExprContext res(engine);
  4779. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4780. bc->AddCode(&res.bc);
  4781. *lvalue = res.type;
  4782. }
  4783. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4784. {
  4785. // Call the default copy operator for script classes
  4786. // This is done differently because the default copy operator
  4787. // is registered as returning int&, but in reality it returns
  4788. // a reference to the object.
  4789. // TODO: Avoid this special case by implementing a copystub for
  4790. // script classes that uses the default copy operator
  4791. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4792. bc->Instr(asBC_PshRPtr);
  4793. }
  4794. else
  4795. {
  4796. // Default copy operator
  4797. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4798. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4799. {
  4800. asCString msg;
  4801. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4802. Error(msg, node);
  4803. return -1;
  4804. }
  4805. // Copy larger data types from a reference
  4806. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4807. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4808. }
  4809. }
  4810. else
  4811. {
  4812. // TODO: The object handle can be stored in a variable as well
  4813. if( !lvalue->dataType.IsReference() )
  4814. {
  4815. Error(TXT_NOT_VALID_REFERENCE, node);
  4816. return -1;
  4817. }
  4818. if( lvalue->dataType.IsFuncdef() )
  4819. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4820. else
  4821. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4822. // Mark variable as initialized
  4823. if( variables )
  4824. {
  4825. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4826. if( v ) v->isInitialized = true;
  4827. }
  4828. }
  4829. return 0;
  4830. }
  4831. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4832. {
  4833. bool conversionDone = false;
  4834. asCArray<int> ops;
  4835. // A ref cast must not remove the constness
  4836. bool isConst = ctx->type.dataType.IsObjectConst();
  4837. // Find a suitable opCast or opImplCast method
  4838. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4839. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4840. {
  4841. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4842. if( (isExplicit && func->name == "opCast") ||
  4843. func->name == "opImplCast" )
  4844. {
  4845. // Is the operator for the output type?
  4846. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4847. continue;
  4848. // Can't call a non-const function on a const object
  4849. if( isConst && !func->IsReadOnly() )
  4850. continue;
  4851. ops.PushLast(func->id);
  4852. }
  4853. }
  4854. // Filter the list by constness to remove const methods if there are matching non-const methods
  4855. FilterConst(ops, !isConst);
  4856. // If there is multiple matches, then pick the most appropriate one
  4857. if (ops.GetLength() > 1)
  4858. {
  4859. // This should only happen if an explicit cast is compiled
  4860. // and the type has both the opCast and opImplCast
  4861. asASSERT(isExplicit);
  4862. asASSERT(ops.GetLength() == 2);
  4863. for (asUINT n = 0; n < ops.GetLength(); n++)
  4864. {
  4865. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4866. if (func->name == "opImplCast")
  4867. {
  4868. ops.RemoveIndex(n);
  4869. n--;
  4870. }
  4871. }
  4872. }
  4873. // Should only have one behaviour for each output type
  4874. if( ops.GetLength() == 1 )
  4875. {
  4876. conversionDone = true;
  4877. if( generateCode )
  4878. {
  4879. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4880. // null, we can create a special CALLSYS instruction that checks
  4881. // if the object pointer is null and if so sets the object register
  4882. // to null directly without executing the function.
  4883. //
  4884. // Alternatively I could force the ref cast behaviours be global
  4885. // functions with 1 parameter, even though they should still be
  4886. // registered with RegisterObjectBehaviour()
  4887. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4888. {
  4889. // Add code to avoid calling the cast behaviour if the handle is already null,
  4890. // because that will raise a null pointer exception due to the cast behaviour
  4891. // being a class method, and the this pointer cannot be null.
  4892. if (!ctx->type.isVariable)
  4893. {
  4894. Dereference(ctx, true);
  4895. ConvertToVariable(ctx);
  4896. }
  4897. // The reference on the stack will not be used
  4898. ctx->bc.Instr(asBC_PopPtr);
  4899. // TODO: runtime optimize: should have immediate comparison for null pointer
  4900. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4901. // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
  4902. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4903. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4904. DeallocateVariable(offset);
  4905. int afterLabel = nextLabel++;
  4906. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4907. // Call the cast operator
  4908. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4909. ctx->bc.Instr(asBC_RDSPtr);
  4910. ctx->type.dataType.MakeReference(false);
  4911. asCArray<asCExprContext *> args;
  4912. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4913. ctx->bc.Instr(asBC_PopPtr);
  4914. int endLabel = nextLabel++;
  4915. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4916. ctx->bc.Label((short)afterLabel);
  4917. // Make a NULL pointer
  4918. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4919. ctx->bc.Label((short)endLabel);
  4920. // Push the reference to the handle on the stack
  4921. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4922. }
  4923. else
  4924. {
  4925. // Value types cannot be null, so there is no need to check for this.
  4926. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4927. // as those are only expected as registered global properties that cannot
  4928. // be modified anyway.
  4929. // Call the cast operator
  4930. asCArray<asCExprContext *> args;
  4931. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4932. }
  4933. }
  4934. else
  4935. {
  4936. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4937. ctx->type.Set(func->returnType);
  4938. }
  4939. }
  4940. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() )
  4941. {
  4942. // Check for the generic ref cast method: void opCast(?&out)
  4943. // This option only works if the expected type is a handle
  4944. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4945. {
  4946. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4947. if( (isExplicit && func->name == "opCast") ||
  4948. func->name == "opImplCast" )
  4949. {
  4950. // Does the operator take the ?&out parameter?
  4951. if( func->returnType.GetTokenType() != ttVoid ||
  4952. func->parameterTypes.GetLength() != 1 ||
  4953. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4954. func->inOutFlags[0] != asTM_OUTREF )
  4955. continue;
  4956. ops.PushLast(func->id);
  4957. }
  4958. }
  4959. // Filter the list by constness to remove const methods if there are matching non-const methods
  4960. FilterConst(ops, !isConst);
  4961. // If there is multiple matches, then pick the most appropriate one
  4962. if (ops.GetLength() > 1)
  4963. {
  4964. // This should only happen if an explicit cast is compiled
  4965. // and the type has both the opCast and opImplCast
  4966. asASSERT(isExplicit);
  4967. asASSERT(ops.GetLength() == 2);
  4968. for (asUINT n = 0; n < ops.GetLength(); n++)
  4969. {
  4970. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4971. if (func->name == "opImplCast")
  4972. {
  4973. ops.RemoveIndex(n);
  4974. n--;
  4975. }
  4976. }
  4977. }
  4978. if( ops.GetLength() == 1 )
  4979. {
  4980. conversionDone = true;
  4981. if( generateCode )
  4982. {
  4983. int afterLabel = 0;
  4984. bool doNullCheck = false;
  4985. bool releaseTempVariable = false;
  4986. asCExprContext tmp(engine);
  4987. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4988. {
  4989. tmp.bc.AddCode(&ctx->bc);
  4990. tmp.Merge(ctx);
  4991. // Add code to avoid calling the cast behaviour if the handle is already null,
  4992. // because that will raise a null pointer exception due to the cast behaviour
  4993. // being a class method, and the this pointer cannot be null.
  4994. doNullCheck = true;
  4995. if (!ctx->type.isVariable)
  4996. {
  4997. Dereference(&tmp, true);
  4998. ConvertToVariable(&tmp);
  4999. releaseTempVariable = true;
  5000. }
  5001. // The reference on the stack will not be used
  5002. tmp.bc.Instr(asBC_PopPtr);
  5003. // TODO: runtime optimize: should have immediate comparison for null pointer
  5004. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  5005. // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
  5006. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  5007. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  5008. DeallocateVariable(offset);
  5009. afterLabel = nextLabel++;
  5010. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  5011. // Place the object pointer on the stack
  5012. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  5013. }
  5014. // Allocate a temporary variable of the requested handle type
  5015. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5016. // Pass the reference of that variable to the function as output parameter
  5017. asCDataType toRef(to);
  5018. toRef.MakeReference(true);
  5019. asCArray<asCExprContext *> args;
  5020. asCExprContext arg(engine);
  5021. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5022. // Don't mark the variable as temporary, so it won't be freed too early
  5023. arg.type.SetVariable(toRef, stackOffset, false);
  5024. arg.type.isLValue = true;
  5025. arg.type.isExplicitHandle = true;
  5026. args.PushLast(&arg);
  5027. // Call the behaviour method
  5028. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5029. if (doNullCheck)
  5030. {
  5031. // Add the call after the null check
  5032. tmp.bc.AddCode(&ctx->bc);
  5033. ctx->bc.AddCode(&tmp.bc);
  5034. int endLabel = nextLabel++;
  5035. ctx->bc.InstrINT(asBC_JMP, endLabel);
  5036. ctx->bc.Label((short)afterLabel);
  5037. // Make a NULL pointer
  5038. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  5039. ctx->bc.Label((short)endLabel);
  5040. }
  5041. // If a temporary variable was allocated in the tmp to convert
  5042. // the input expression to a variable, it must be released here
  5043. if (releaseTempVariable && tmp.type.isTemporary)
  5044. ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
  5045. // Use the reference to the variable as the result of the expression
  5046. // Now we can mark the variable as temporary
  5047. ctx->type.SetVariable(toRef, stackOffset, true);
  5048. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5049. }
  5050. else
  5051. {
  5052. // All casts are legal
  5053. ctx->type.Set(to);
  5054. }
  5055. }
  5056. }
  5057. // If the script object didn't implement a matching opCast or opImplCast
  5058. // then check if the desired type is part of the hierarchy
  5059. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  5060. {
  5061. // We need it to be a reference
  5062. if( !ctx->type.dataType.IsReference() )
  5063. {
  5064. asCDataType toRef = ctx->type.dataType;
  5065. toRef.MakeReference(true);
  5066. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  5067. }
  5068. if( isExplicit )
  5069. {
  5070. // Allow dynamic cast between object handles (only for script objects).
  5071. // At run time this may result in a null handle,
  5072. // which when used will throw an exception
  5073. conversionDone = true;
  5074. if( generateCode )
  5075. {
  5076. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  5077. // Allocate a temporary variable for the returned object
  5078. int returnOffset = AllocateVariable(to, true);
  5079. // Move the pointer from the object register to the temporary variable
  5080. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  5081. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  5082. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5083. ctx->type.SetVariable(to, returnOffset, true);
  5084. ctx->type.dataType.MakeReference(true);
  5085. }
  5086. else
  5087. {
  5088. ctx->type.dataType = to;
  5089. ctx->type.dataType.MakeReference(true);
  5090. }
  5091. }
  5092. else
  5093. {
  5094. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  5095. {
  5096. conversionDone = true;
  5097. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5098. }
  5099. }
  5100. // A ref cast must not remove the constness
  5101. if( isConst )
  5102. ctx->type.dataType.MakeHandleToConst(true);
  5103. }
  5104. return conversionDone;
  5105. }
  5106. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5107. {
  5108. asCDataType to = toOrig;
  5109. to.MakeReference(false);
  5110. asASSERT( !ctx->type.dataType.IsReference() );
  5111. // Maybe no conversion is needed
  5112. if( to.IsEqualExceptConst(ctx->type.dataType) )
  5113. {
  5114. // A primitive is const or not
  5115. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5116. return asCC_NO_CONV;
  5117. }
  5118. // Is the conversion an ambiguous enum value?
  5119. if( ctx->enumValue != "" )
  5120. {
  5121. if( to.IsEnumType() )
  5122. {
  5123. // Attempt to resolve an ambiguous enum value
  5124. asCDataType out;
  5125. asDWORD value;
  5126. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  5127. {
  5128. ctx->type.SetConstantDW(out, value);
  5129. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5130. // Reset the enum value since we no longer need it
  5131. ctx->enumValue = "";
  5132. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  5133. return asCC_NO_CONV;
  5134. }
  5135. }
  5136. // The enum value is ambiguous
  5137. if( node && generateCode )
  5138. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  5139. // Set a dummy to allow the compiler to try to continue the conversion
  5140. ctx->type.SetDummy();
  5141. }
  5142. // Determine the cost of this conversion
  5143. asUINT cost = asCC_NO_CONV;
  5144. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5145. cost = asCC_INT_FLOAT_CONV;
  5146. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  5147. cost = asCC_INT_FLOAT_CONV;
  5148. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  5149. cost = asCC_ENUM_SAME_SIZE_CONV;
  5150. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  5151. cost = asCC_ENUM_DIFF_SIZE_CONV;
  5152. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  5153. cost = asCC_SIGNED_CONV;
  5154. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  5155. cost = asCC_SIGNED_CONV;
  5156. else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
  5157. cost = asCC_PRIMITIVE_SIZE_CONV;
  5158. // Start by implicitly converting constant values
  5159. if( ctx->type.isConstant )
  5160. {
  5161. ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType);
  5162. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5163. return cost;
  5164. }
  5165. // Allow implicit conversion between numbers
  5166. if( generateCode )
  5167. {
  5168. // When generating the code the decision has already been made, so we don't bother determining the cost
  5169. // Convert smaller types to 32bit first
  5170. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  5171. if( s < 4 )
  5172. {
  5173. ConvertToTempVariable(ctx);
  5174. if( ctx->type.dataType.IsIntegerType() )
  5175. {
  5176. if( s == 1 )
  5177. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  5178. else if( s == 2 )
  5179. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  5180. ctx->type.dataType.SetTokenType(ttInt);
  5181. }
  5182. else if( ctx->type.dataType.IsUnsignedType() )
  5183. {
  5184. if( s == 1 )
  5185. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  5186. else if( s == 2 )
  5187. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  5188. ctx->type.dataType.SetTokenType(ttUInt);
  5189. }
  5190. }
  5191. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5192. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5193. {
  5194. if( ctx->type.dataType.IsIntegerType() ||
  5195. ctx->type.dataType.IsUnsignedType() )
  5196. {
  5197. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5198. {
  5199. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5200. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5201. }
  5202. else
  5203. {
  5204. ConvertToTempVariable(ctx);
  5205. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5206. int offset = AllocateVariable(to, true);
  5207. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5208. ctx->type.SetVariable(to, offset, true);
  5209. }
  5210. }
  5211. else if( ctx->type.dataType.IsFloatType() )
  5212. {
  5213. ConvertToTempVariable(ctx);
  5214. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  5215. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5216. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5217. if( convType != asIC_EXPLICIT_VAL_CAST )
  5218. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5219. }
  5220. else if( ctx->type.dataType.IsDoubleType() )
  5221. {
  5222. ConvertToTempVariable(ctx);
  5223. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5224. int offset = AllocateVariable(to, true);
  5225. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  5226. ctx->type.SetVariable(to, offset, true);
  5227. if( convType != asIC_EXPLICIT_VAL_CAST )
  5228. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5229. }
  5230. // Convert to smaller integer if necessary
  5231. s = to.GetSizeInMemoryBytes();
  5232. if( s < 4 )
  5233. {
  5234. ConvertToTempVariable(ctx);
  5235. if( s == 1 )
  5236. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5237. else if( s == 2 )
  5238. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5239. }
  5240. }
  5241. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5242. {
  5243. if( ctx->type.dataType.IsIntegerType() ||
  5244. ctx->type.dataType.IsUnsignedType() )
  5245. {
  5246. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5247. {
  5248. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5249. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5250. }
  5251. else
  5252. {
  5253. ConvertToTempVariable(ctx);
  5254. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5255. int offset = AllocateVariable(to, true);
  5256. if( ctx->type.dataType.IsUnsignedType() )
  5257. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5258. else
  5259. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5260. ctx->type.SetVariable(to, offset, true);
  5261. }
  5262. }
  5263. else if( ctx->type.dataType.IsFloatType() )
  5264. {
  5265. ConvertToTempVariable(ctx);
  5266. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5267. int offset = AllocateVariable(to, true);
  5268. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5269. ctx->type.SetVariable(to, offset, true);
  5270. if( convType != asIC_EXPLICIT_VAL_CAST )
  5271. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5272. }
  5273. else if( ctx->type.dataType.IsDoubleType() )
  5274. {
  5275. ConvertToTempVariable(ctx);
  5276. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  5277. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5278. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5279. if( convType != asIC_EXPLICIT_VAL_CAST )
  5280. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5281. }
  5282. }
  5283. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5284. {
  5285. if( ctx->type.dataType.IsIntegerType() ||
  5286. ctx->type.dataType.IsUnsignedType() )
  5287. {
  5288. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5289. {
  5290. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5291. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5292. }
  5293. else
  5294. {
  5295. ConvertToTempVariable(ctx);
  5296. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5297. int offset = AllocateVariable(to, true);
  5298. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5299. ctx->type.SetVariable(to, offset, true);
  5300. }
  5301. }
  5302. else if( ctx->type.dataType.IsFloatType() )
  5303. {
  5304. ConvertToTempVariable(ctx);
  5305. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  5306. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5307. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5308. if( convType != asIC_EXPLICIT_VAL_CAST )
  5309. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5310. }
  5311. else if( ctx->type.dataType.IsDoubleType() )
  5312. {
  5313. ConvertToTempVariable(ctx);
  5314. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5315. int offset = AllocateVariable(to, true);
  5316. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5317. ctx->type.SetVariable(to, offset, true);
  5318. if( convType != asIC_EXPLICIT_VAL_CAST )
  5319. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5320. }
  5321. // Convert to smaller integer if necessary
  5322. s = to.GetSizeInMemoryBytes();
  5323. if( s < 4 )
  5324. {
  5325. ConvertToTempVariable(ctx);
  5326. if( s == 1 )
  5327. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5328. else if( s == 2 )
  5329. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5330. }
  5331. }
  5332. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5333. {
  5334. if( ctx->type.dataType.IsIntegerType() ||
  5335. ctx->type.dataType.IsUnsignedType() )
  5336. {
  5337. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5338. {
  5339. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5340. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5341. }
  5342. else
  5343. {
  5344. ConvertToTempVariable(ctx);
  5345. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5346. int offset = AllocateVariable(to, true);
  5347. if( ctx->type.dataType.IsUnsignedType() )
  5348. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5349. else
  5350. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5351. ctx->type.SetVariable(to, offset, true);
  5352. }
  5353. }
  5354. else if( ctx->type.dataType.IsFloatType() )
  5355. {
  5356. ConvertToTempVariable(ctx);
  5357. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5358. int offset = AllocateVariable(to, true);
  5359. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5360. ctx->type.SetVariable(to, offset, true);
  5361. if( convType != asIC_EXPLICIT_VAL_CAST )
  5362. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5363. }
  5364. else if( ctx->type.dataType.IsDoubleType() )
  5365. {
  5366. ConvertToTempVariable(ctx);
  5367. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  5368. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5369. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5370. if( convType != asIC_EXPLICIT_VAL_CAST )
  5371. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5372. }
  5373. }
  5374. else if( to.IsFloatType() )
  5375. {
  5376. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5377. {
  5378. ConvertToTempVariable(ctx);
  5379. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5380. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5381. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5382. }
  5383. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5384. {
  5385. ConvertToTempVariable(ctx);
  5386. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5387. int offset = AllocateVariable(to, true);
  5388. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5389. ctx->type.SetVariable(to, offset, true);
  5390. }
  5391. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5392. {
  5393. ConvertToTempVariable(ctx);
  5394. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5395. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5396. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5397. }
  5398. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5399. {
  5400. ConvertToTempVariable(ctx);
  5401. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5402. int offset = AllocateVariable(to, true);
  5403. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5404. ctx->type.SetVariable(to, offset, true);
  5405. }
  5406. else if( ctx->type.dataType.IsDoubleType() )
  5407. {
  5408. ConvertToTempVariable(ctx);
  5409. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5410. int offset = AllocateVariable(to, true);
  5411. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5412. ctx->type.SetVariable(to, offset, true);
  5413. }
  5414. }
  5415. else if( to.IsDoubleType() )
  5416. {
  5417. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5418. {
  5419. ConvertToTempVariable(ctx);
  5420. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5421. int offset = AllocateVariable(to, true);
  5422. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5423. ctx->type.SetVariable(to, offset, true);
  5424. }
  5425. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5426. {
  5427. ConvertToTempVariable(ctx);
  5428. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5429. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5430. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5431. }
  5432. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5433. {
  5434. ConvertToTempVariable(ctx);
  5435. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5436. int offset = AllocateVariable(to, true);
  5437. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5438. ctx->type.SetVariable(to, offset, true);
  5439. }
  5440. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5441. {
  5442. ConvertToTempVariable(ctx);
  5443. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5444. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5445. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5446. }
  5447. else if( ctx->type.dataType.IsFloatType() )
  5448. {
  5449. ConvertToTempVariable(ctx);
  5450. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5451. int offset = AllocateVariable(to, true);
  5452. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5453. ctx->type.SetVariable(to, offset, true);
  5454. }
  5455. }
  5456. }
  5457. else
  5458. {
  5459. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5460. to.IsFloatType() || to.IsDoubleType() ||
  5461. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5462. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5463. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5464. {
  5465. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5466. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5467. }
  5468. }
  5469. // Primitive types on the stack, can be const or non-const
  5470. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5471. return cost;
  5472. }
  5473. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5474. {
  5475. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5476. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5477. // Check that the lambda has the correct amount of arguments
  5478. asUINT count = 0;
  5479. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5480. while( argNode->nodeType != snStatementBlock )
  5481. {
  5482. // Check if the specified parameter types match the funcdef
  5483. if (argNode->nodeType == snDataType)
  5484. {
  5485. asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType);
  5486. asETypeModifiers inOutFlag;
  5487. dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
  5488. if (count >= funcDef->parameterTypes.GetLength() ||
  5489. funcDef->parameterTypes[count] != dt ||
  5490. funcDef->inOutFlags[count] != inOutFlag)
  5491. return asCC_NO_CONV;
  5492. argNode = argNode->next;
  5493. }
  5494. if( argNode->nodeType == snIdentifier )
  5495. count++;
  5496. argNode = argNode->next;
  5497. }
  5498. if (funcDef->parameterTypes.GetLength() != count)
  5499. return asCC_NO_CONV;
  5500. asASSERT(argNode->nodeType == snStatementBlock);
  5501. // The Lambda can be used as this funcdef
  5502. ctx->type.dataType = to;
  5503. if( generateCode )
  5504. {
  5505. // Build a unique name for the anonymous function
  5506. asCString name;
  5507. if( m_globalVar )
  5508. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5509. else
  5510. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5511. // Register the lambda with the builder for later compilation
  5512. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace, outFunc->IsShared());
  5513. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5514. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5515. // Clear the expression node as it is no longer valid
  5516. ctx->exprNode = 0;
  5517. }
  5518. return asCC_CONST_CONV;
  5519. }
  5520. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5521. {
  5522. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5523. ctx->type.dataType.IsNullHandle() ||
  5524. ctx->IsAnonymousInitList() );
  5525. if( to.IsFuncdef() && ctx->IsLambda() )
  5526. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5527. if (ctx->IsAnonymousInitList())
  5528. {
  5529. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5530. {
  5531. if (generateCode)
  5532. CompileAnonymousInitList(ctx->exprNode, ctx, to);
  5533. else
  5534. ctx->type.dataType = to;
  5535. }
  5536. return asCC_NO_CONV;
  5537. }
  5538. // No conversion from void to any other type
  5539. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5540. return asCC_NO_CONV;
  5541. // No conversion from class method to any type (it requires delegate)
  5542. if( ctx->IsClassMethod() )
  5543. return asCC_NO_CONV;
  5544. // Do we want a var type?
  5545. if( to.GetTokenType() == ttQuestion )
  5546. {
  5547. // Any type can be converted to a var type, but only when not generating code
  5548. asASSERT( !generateCode );
  5549. ctx->type.dataType = to;
  5550. return asCC_VARIABLE_CONV;
  5551. }
  5552. // Do we want a primitive?
  5553. else if( to.IsPrimitive() )
  5554. {
  5555. if( !ctx->type.dataType.IsPrimitive() )
  5556. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5557. else
  5558. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5559. }
  5560. else // The target is a complex type
  5561. {
  5562. if( ctx->type.dataType.IsPrimitive() )
  5563. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5564. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5565. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5566. }
  5567. return asCC_NO_CONV;
  5568. }
  5569. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5570. {
  5571. if( ctx->type.isExplicitHandle )
  5572. {
  5573. // An explicit handle cannot be converted to a primitive
  5574. if( convType != asIC_IMPLICIT_CONV && node )
  5575. {
  5576. asCString str;
  5577. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5578. Error(str, node);
  5579. }
  5580. return asCC_NO_CONV;
  5581. }
  5582. // Find matching value cast behaviours
  5583. // Here we're only interested in those that convert the type to a primitive type
  5584. asCArray<int> funcs;
  5585. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5586. if( ot == 0 )
  5587. {
  5588. if( convType != asIC_IMPLICIT_CONV && node )
  5589. {
  5590. asCString str;
  5591. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5592. Error(str, node);
  5593. }
  5594. return asCC_NO_CONV;
  5595. }
  5596. if( convType == asIC_EXPLICIT_VAL_CAST )
  5597. {
  5598. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5599. {
  5600. // accept both implicit and explicit cast
  5601. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5602. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5603. mthd->parameterTypes.GetLength() == 0 &&
  5604. mthd->returnType.IsPrimitive() )
  5605. funcs.PushLast(ot->methods[n]);
  5606. }
  5607. }
  5608. else
  5609. {
  5610. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5611. {
  5612. // accept only implicit cast
  5613. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5614. if( mthd->name == "opImplConv" &&
  5615. mthd->parameterTypes.GetLength() == 0 &&
  5616. mthd->returnType.IsPrimitive() )
  5617. funcs.PushLast(ot->methods[n]);
  5618. }
  5619. }
  5620. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5621. int funcId = 0;
  5622. if( to.IsMathType() )
  5623. {
  5624. // This matrix describes the priorities of the types to search for, for each target type
  5625. // The first column is the target type, the priorities goes from left to right
  5626. eTokenType matchMtx[10][10] =
  5627. {
  5628. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5629. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5630. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5631. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5632. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5633. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5634. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5635. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5636. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5637. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5638. };
  5639. // Which row to use?
  5640. eTokenType *row = 0;
  5641. for( unsigned int type = 0; type < 10; type++ )
  5642. {
  5643. if( to.GetTokenType() == matchMtx[type][0] )
  5644. {
  5645. row = &matchMtx[type][0];
  5646. break;
  5647. }
  5648. }
  5649. // Find the best matching cast operator
  5650. if( row )
  5651. {
  5652. asCDataType target(to);
  5653. // Priority goes from left to right in the matrix
  5654. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5655. {
  5656. target.SetTokenType(row[attempt]);
  5657. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5658. {
  5659. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5660. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5661. {
  5662. funcId = funcs[n];
  5663. break;
  5664. }
  5665. }
  5666. }
  5667. }
  5668. }
  5669. else
  5670. {
  5671. // Only accept the exact conversion for non-math types
  5672. // Find the matching cast operator
  5673. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5674. {
  5675. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5676. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5677. {
  5678. funcId = funcs[n];
  5679. break;
  5680. }
  5681. }
  5682. }
  5683. // Did we find a suitable function?
  5684. if( funcId != 0 )
  5685. {
  5686. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5687. if( generateCode )
  5688. {
  5689. Dereference(ctx, true);
  5690. PerformFunctionCall(funcId, ctx);
  5691. }
  5692. else
  5693. ctx->type.Set(descr->returnType);
  5694. // Allow one more implicit conversion to another primitive type
  5695. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5696. }
  5697. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5698. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5699. funcs.SetLength(0);
  5700. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5701. {
  5702. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5703. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5704. func->name == "opImplConv" )
  5705. {
  5706. // Does the operator take the ?&out parameter?
  5707. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5708. func->parameterTypes.GetLength() != 1 ||
  5709. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5710. func->inOutFlags[0] != asTM_OUTREF )
  5711. continue;
  5712. funcs.PushLast(ot->methods[n]);
  5713. }
  5714. }
  5715. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5716. // If there are multiple valid value casts, then we must choose the most appropriate one
  5717. if (funcs.GetLength() > 1)
  5718. {
  5719. // This should only happen in case of explicit value cast and
  5720. // the application has registered both opImplConv and opConv
  5721. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5722. asASSERT(funcs.GetLength() == 2);
  5723. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5724. {
  5725. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5726. if (func->name == "opImplConv")
  5727. {
  5728. funcs.RemoveIndex(n);
  5729. n--;
  5730. }
  5731. }
  5732. }
  5733. if( funcs.GetLength() == 1 )
  5734. {
  5735. if( generateCode )
  5736. {
  5737. // Allocate a temporary variable of the requested type
  5738. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5739. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5740. // Pass the reference of that variable to the function as output parameter
  5741. asCDataType toRef(to);
  5742. toRef.MakeReference(true);
  5743. toRef.MakeReadOnly(false);
  5744. asCArray<asCExprContext *> args;
  5745. asCExprContext arg(engine);
  5746. // Don't mark the variable as temporary, so it won't be freed too early
  5747. arg.type.SetVariable(toRef, stackOffset, false);
  5748. arg.type.isLValue = true;
  5749. arg.exprNode = node;
  5750. args.PushLast(&arg);
  5751. // Call the behaviour method
  5752. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5753. // Use the reference to the variable as the result of the expression
  5754. // Now we can mark the variable as temporary
  5755. toRef.MakeReference(false);
  5756. ctx->type.SetVariable(toRef, stackOffset, true);
  5757. }
  5758. else
  5759. ctx->type.Set(to);
  5760. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5761. }
  5762. if( convType != asIC_IMPLICIT_CONV && node )
  5763. {
  5764. asCString str;
  5765. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5766. Error(str, node);
  5767. }
  5768. return asCC_NO_CONV;
  5769. }
  5770. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5771. {
  5772. // Convert null to any object type handle, but not to a non-handle type
  5773. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5774. {
  5775. if( to.IsObjectHandle() )
  5776. {
  5777. ctx->type.dataType = to;
  5778. return asCC_REF_CONV;
  5779. }
  5780. return asCC_NO_CONV;
  5781. }
  5782. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5783. // First attempt to convert the base type without instantiating another instance
  5784. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5785. {
  5786. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5787. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5788. {
  5789. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5790. return asCC_REF_CONV;
  5791. }
  5792. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5793. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5794. {
  5795. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5796. return asCC_REF_CONV;
  5797. }
  5798. // If the types are not equal yet, then we may still be able to find a reference cast
  5799. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5800. {
  5801. // We may still be able to find an implicit ref cast behaviour
  5802. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5803. // Was the conversion done?
  5804. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5805. return asCC_REF_CONV;
  5806. }
  5807. }
  5808. // Convert matching function types
  5809. if( to.IsFuncdef() )
  5810. {
  5811. // If the input expression is already a funcdef, check if it can be converted
  5812. if( ctx->type.dataType.IsFuncdef() &&
  5813. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5814. {
  5815. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5816. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5817. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5818. {
  5819. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5820. return asCC_REF_CONV;
  5821. }
  5822. }
  5823. // If the input expression is a deferred function ref, check if there is a matching func
  5824. if( ctx->methodName != "" )
  5825. {
  5826. // Determine the namespace
  5827. asSNameSpace *ns = 0;
  5828. asCString name = "";
  5829. int pos = ctx->methodName.FindLast("::");
  5830. if( pos >= 0 )
  5831. {
  5832. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5833. // Trim off the last ::
  5834. if( nsName.GetLength() > 2 )
  5835. nsName.SetLength(nsName.GetLength()-2);
  5836. ns = DetermineNameSpace(nsName);
  5837. name = ctx->methodName.SubString(pos+2);
  5838. }
  5839. else
  5840. {
  5841. DetermineNameSpace("");
  5842. name = ctx->methodName;
  5843. }
  5844. asCArray<int> funcs;
  5845. if( ns )
  5846. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5847. // Check if any of the functions have perfect match
  5848. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5849. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5850. {
  5851. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5852. if( toFunc->IsSignatureExceptNameEqual(func) )
  5853. {
  5854. if( generateCode )
  5855. {
  5856. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5857. // Make sure the identified function is shared if we're compiling a shared function
  5858. if( !func->IsShared() && outFunc->IsShared() )
  5859. {
  5860. asCString msg;
  5861. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5862. Error(msg, node);
  5863. }
  5864. }
  5865. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5866. return asCC_REF_CONV;
  5867. }
  5868. }
  5869. }
  5870. }
  5871. return asCC_NO_CONV;
  5872. }
  5873. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5874. {
  5875. asUINT cost = asCC_NO_CONV;
  5876. // If the base type is still different, and we are allowed to instance
  5877. // another object then we can try an implicit value cast
  5878. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5879. {
  5880. // TODO: Implement support for implicit constructor/factory
  5881. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5882. if( ot == 0 )
  5883. return cost;
  5884. asCArray<int> funcs;
  5885. if( convType == asIC_EXPLICIT_VAL_CAST )
  5886. {
  5887. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5888. {
  5889. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5890. // accept both implicit and explicit cast
  5891. if( (func->name == "opConv" ||
  5892. func->name == "opImplConv") &&
  5893. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5894. func->parameterTypes.GetLength() == 0 )
  5895. funcs.PushLast(ot->methods[n]);
  5896. }
  5897. }
  5898. else
  5899. {
  5900. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5901. {
  5902. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5903. // accept only implicit cast
  5904. if( func->name == "opImplConv" &&
  5905. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5906. func->parameterTypes.GetLength() == 0 )
  5907. funcs.PushLast(ot->methods[n]);
  5908. }
  5909. }
  5910. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5911. // If there are multiple valid value casts, then we must choose the most appropriate one
  5912. if (funcs.GetLength() > 1)
  5913. {
  5914. // This should only happen in case of explicit value cast and
  5915. // the application has registered both opImplConv and opConv
  5916. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5917. asASSERT(funcs.GetLength() == 2);
  5918. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5919. {
  5920. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5921. if (func->name == "opImplConv")
  5922. {
  5923. funcs.RemoveIndex(n);
  5924. n--;
  5925. }
  5926. }
  5927. }
  5928. if( funcs.GetLength() == 1 )
  5929. {
  5930. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5931. if( generateCode )
  5932. {
  5933. Dereference(ctx, true);
  5934. bool useVariable = false;
  5935. int stackOffset = 0;
  5936. if( f->DoesReturnOnStack() )
  5937. {
  5938. useVariable = true;
  5939. stackOffset = AllocateVariable(f->returnType, true);
  5940. // Push the pointer to the pre-allocated space for the return value
  5941. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5942. // The object pointer is already on the stack, but should be the top
  5943. // one, so we need to swap the pointers in order to get the correct
  5944. ctx->bc.Instr(asBC_SwapPtr);
  5945. }
  5946. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5947. }
  5948. else
  5949. ctx->type.Set(f->returnType);
  5950. cost = asCC_TO_OBJECT_CONV;
  5951. }
  5952. else
  5953. {
  5954. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5955. // Look for a value cast with variable type
  5956. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5957. {
  5958. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5959. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5960. func->name == "opImplConv" )
  5961. {
  5962. // Does the operator take the ?&out parameter?
  5963. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5964. func->parameterTypes.GetLength() != 1 ||
  5965. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5966. func->inOutFlags[0] != asTM_OUTREF )
  5967. continue;
  5968. funcs.PushLast(ot->methods[n]);
  5969. }
  5970. }
  5971. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5972. // If there are multiple valid value casts, then we must choose the most appropriate one
  5973. if (funcs.GetLength() > 1)
  5974. {
  5975. // This should only happen in case of explicit value cast and
  5976. // the application has registered both opImplConv and opConv
  5977. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5978. asASSERT(funcs.GetLength() == 2);
  5979. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5980. {
  5981. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5982. if (func->name == "opImplConv")
  5983. {
  5984. funcs.RemoveIndex(n);
  5985. n--;
  5986. }
  5987. }
  5988. }
  5989. if( funcs.GetLength() == 1 )
  5990. {
  5991. cost = asCC_TO_OBJECT_CONV;
  5992. if( generateCode )
  5993. {
  5994. // Allocate a temporary variable of the requested type
  5995. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5996. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5997. // Pass the reference of that variable to the function as output parameter
  5998. asCDataType toRef(to);
  5999. toRef.MakeReference(false);
  6000. asCExprContext arg(engine);
  6001. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6002. // If this an object on the heap, the pointer must be dereferenced
  6003. if( IsVariableOnHeap(stackOffset) )
  6004. arg.bc.Instr(asBC_RDSPtr);
  6005. // Don't mark the variable as temporary, so it won't be freed too early
  6006. arg.type.SetVariable(toRef, stackOffset, false);
  6007. arg.type.isLValue = true;
  6008. arg.exprNode = node;
  6009. // Mark the argument as clean, so that MakeFunctionCall knows it
  6010. // doesn't have to make a copy of it in order to protect the value
  6011. arg.isCleanArg = true;
  6012. // Call the behaviour method
  6013. asCArray<asCExprContext *> args;
  6014. args.PushLast(&arg);
  6015. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  6016. // Use the reference to the variable as the result of the expression
  6017. // Now we can mark the variable as temporary
  6018. ctx->type.SetVariable(toRef, stackOffset, true);
  6019. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6020. }
  6021. else
  6022. {
  6023. // All casts are legal
  6024. ctx->type.Set(to);
  6025. }
  6026. }
  6027. else if( CastToObjectType(to.GetTypeInfo()) )
  6028. {
  6029. // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type
  6030. if( to.GetTypeInfo()->flags & asOBJ_REF )
  6031. funcs = CastToObjectType(to.GetTypeInfo())->beh.factories;
  6032. else
  6033. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6034. // If not explicit cast, remove any explicit conversion constructors
  6035. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6036. {
  6037. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6038. if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) )
  6039. funcs.RemoveIndex(n--);
  6040. }
  6041. asCArray<asCExprContext *> args;
  6042. args.PushLast(ctx);
  6043. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6044. // Did we find a matching constructor?
  6045. if (funcs.GetLength() == 1)
  6046. {
  6047. if (generateCode)
  6048. {
  6049. // TODO: This should really reuse the code from CompileConstructCall
  6050. // Allocate the new object
  6051. asCExprValue tempObj;
  6052. asCExprContext e(engine);
  6053. bool onHeap = false;
  6054. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6055. {
  6056. tempObj.dataType = to;
  6057. tempObj.dataType.MakeReference(false);
  6058. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6059. tempObj.dataType.MakeReference(true);
  6060. tempObj.isTemporary = true;
  6061. tempObj.isVariable = true;
  6062. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6063. // Push the address of the object on the stack
  6064. if (onHeap)
  6065. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6066. }
  6067. PrepareFunctionCall(funcs[0], &e.bc, args);
  6068. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6069. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6070. {
  6071. // If the object is allocated on the stack, then call the constructor as a normal function
  6072. if (onHeap)
  6073. {
  6074. int offset = 0;
  6075. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6076. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6077. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6078. }
  6079. else
  6080. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6081. }
  6082. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6083. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6084. {
  6085. // Add tag that the object has been initialized
  6086. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6087. // The constructor doesn't return anything,
  6088. // so we have to manually inform the type of
  6089. // the return value
  6090. e.type = tempObj;
  6091. if (!onHeap)
  6092. e.type.dataType.MakeReference(false);
  6093. // Push the address of the object on the stack again
  6094. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6095. }
  6096. MergeExprBytecodeAndType(ctx, &e);
  6097. }
  6098. else
  6099. {
  6100. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6101. }
  6102. }
  6103. }
  6104. }
  6105. }
  6106. return cost;
  6107. }
  6108. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  6109. {
  6110. // First try a ref cast
  6111. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  6112. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  6113. // construct the object through any of the available constructors (except those marked as explicit)
  6114. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6115. {
  6116. asCArray<int> funcs;
  6117. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6118. // Don't allow use of explicit constructors/factories in implicit conversions
  6119. if (convType == asIC_IMPLICIT_CONV)
  6120. {
  6121. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6122. {
  6123. asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]);
  6124. if (desc->IsExplicit())
  6125. funcs.RemoveIndex(n--);
  6126. }
  6127. }
  6128. asCArray<asCExprContext *> args;
  6129. args.PushLast(ctx);
  6130. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6131. // Did we find a matching constructor?
  6132. if( funcs.GetLength() == 1 )
  6133. {
  6134. if( generateCode )
  6135. {
  6136. // If the ASHANDLE receives a variable type parameter, then we need to
  6137. // make sure the expression is treated as a handle and not as a value
  6138. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  6139. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  6140. {
  6141. if( !ctx->type.isExplicitHandle )
  6142. {
  6143. asCDataType toHandle = ctx->type.dataType;
  6144. toHandle.MakeHandle(true);
  6145. toHandle.MakeReference(true);
  6146. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  6147. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  6148. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6149. }
  6150. ctx->type.isExplicitHandle = true;
  6151. }
  6152. // TODO: This should really reuse the code from CompileConstructCall
  6153. // Allocate the new object
  6154. asCExprValue tempObj;
  6155. tempObj.dataType = to;
  6156. tempObj.dataType.MakeReference(false);
  6157. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6158. tempObj.dataType.MakeReference(true);
  6159. tempObj.isTemporary = true;
  6160. tempObj.isVariable = true;
  6161. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6162. // Push the address of the object on the stack
  6163. asCExprContext e(engine);
  6164. if( onHeap )
  6165. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6166. PrepareFunctionCall(funcs[0], &e.bc, args);
  6167. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6168. // If the object is allocated on the stack, then call the constructor as a normal function
  6169. if( onHeap )
  6170. {
  6171. int offset = 0;
  6172. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6173. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6174. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6175. }
  6176. else
  6177. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6178. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6179. // Add tag that the object has been initialized
  6180. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6181. // The constructor doesn't return anything,
  6182. // so we have to manually inform the type of
  6183. // the return value
  6184. e.type = tempObj;
  6185. if( !onHeap )
  6186. e.type.dataType.MakeReference(false);
  6187. // Push the address of the object on the stack again
  6188. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6189. MergeExprBytecodeAndType(ctx, &e);
  6190. }
  6191. else
  6192. {
  6193. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6194. }
  6195. }
  6196. }
  6197. // If the base type is still different, and we are allowed to instance
  6198. // another object then we can try an implicit value cast
  6199. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6200. {
  6201. // Attempt implicit value cast
  6202. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  6203. }
  6204. // If we still haven't converted the base type to the correct type, then there is
  6205. // no need to continue as it is not possible to do the conversion
  6206. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  6207. return asCC_NO_CONV;
  6208. if( to.IsObjectHandle() )
  6209. {
  6210. // There is no extra cost in converting to a handle
  6211. // reference to handle -> handle
  6212. // reference -> handle
  6213. // object -> handle
  6214. // handle -> reference to handle
  6215. // reference -> reference to handle
  6216. // object -> reference to handle
  6217. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
  6218. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
  6219. {
  6220. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6221. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6222. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6223. {
  6224. if (generateCode)
  6225. PrepareTemporaryVariable(node, ctx);
  6226. else
  6227. {
  6228. ctx->type.dataType.MakeReadOnly(false);
  6229. ctx->type.isConstant = false;
  6230. }
  6231. // Add the cost for the copy
  6232. cost += asCC_TO_OBJECT_CONV;
  6233. }
  6234. else if( convType != asIC_IMPLICIT_CONV )
  6235. {
  6236. asASSERT(node);
  6237. asCString str;
  6238. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  6239. Error(str, node);
  6240. }
  6241. }
  6242. if( !ctx->type.dataType.IsObjectHandle() )
  6243. {
  6244. // An object type can be directly converted to a handle of the
  6245. // same type by doing a ref copy to a new variable
  6246. if( ctx->type.dataType.SupportHandles() )
  6247. {
  6248. asCDataType dt = ctx->type.dataType;
  6249. dt.MakeHandle(true);
  6250. dt.MakeReference(false);
  6251. if( generateCode )
  6252. {
  6253. // If the expression is already a local variable, then it is not
  6254. // necessary to do a ref copy, as the ref objects on the stack are
  6255. // really handles, only the handles cannot be modified.
  6256. if( ctx->type.isVariable )
  6257. {
  6258. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  6259. ctx->type.dataType.MakeReadOnly(false);
  6260. ctx->type.dataType.MakeHandle(true);
  6261. ctx->type.dataType.MakeReadOnly(true);
  6262. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  6263. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6264. {
  6265. ctx->bc.Instr(asBC_PopPtr);
  6266. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  6267. ctx->type.dataType.MakeReference(true);
  6268. }
  6269. else if( ctx->type.dataType.IsReference() )
  6270. {
  6271. ctx->bc.Instr(asBC_RDSPtr);
  6272. ctx->type.dataType.MakeReference(false);
  6273. }
  6274. }
  6275. else
  6276. {
  6277. int offset = AllocateVariable(dt, true);
  6278. if( ctx->type.dataType.IsReference() )
  6279. ctx->bc.Instr(asBC_RDSPtr);
  6280. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6281. if (dt.IsFuncdef())
  6282. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  6283. else
  6284. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  6285. ctx->bc.Instr(asBC_PopPtr);
  6286. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6287. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6288. if( to.IsReference() )
  6289. dt.MakeReference(true);
  6290. else
  6291. ctx->bc.Instr(asBC_RDSPtr);
  6292. ctx->type.SetVariable(dt, offset, true);
  6293. }
  6294. }
  6295. else
  6296. ctx->type.dataType = dt;
  6297. // When this conversion is done the expression is no longer an lvalue
  6298. ctx->type.isLValue = false;
  6299. }
  6300. }
  6301. if( ctx->type.dataType.IsObjectHandle() )
  6302. {
  6303. // A handle to non-const can be converted to a
  6304. // handle to const, but not the other way
  6305. if( to.IsHandleToConst() )
  6306. ctx->type.dataType.MakeHandleToConst(true);
  6307. // A const handle can be converted to a non-const
  6308. // handle and vice versa as the handle is just a value
  6309. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6310. }
  6311. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6312. {
  6313. if( generateCode )
  6314. {
  6315. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6316. // If the input type is a handle, then a simple ref copy is enough
  6317. bool isExplicitHandle = ctx->type.isExplicitHandle;
  6318. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  6319. // If the input type is read-only we'll need to temporarily
  6320. // remove this constness, otherwise the assignment will fail
  6321. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6322. ctx->type.dataType.MakeReadOnly(false);
  6323. // If the object already is a temporary variable, then the copy
  6324. // doesn't have to be made as it is already a unique object
  6325. PrepareTemporaryVariable(node, ctx);
  6326. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6327. ctx->type.isExplicitHandle = isExplicitHandle;
  6328. }
  6329. // A non-reference can be converted to a reference,
  6330. // by putting the value in a temporary variable
  6331. ctx->type.dataType.MakeReference(true);
  6332. // Since it is a new temporary variable it doesn't have to be const
  6333. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6334. }
  6335. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  6336. {
  6337. Dereference(ctx, generateCode);
  6338. }
  6339. }
  6340. else // if( !to.IsObjectHandle() )
  6341. {
  6342. if( !to.IsReference() )
  6343. {
  6344. // reference to handle -> object
  6345. // handle -> object
  6346. // reference -> object
  6347. // An implicit handle can be converted to an object by adding a check for null pointer
  6348. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6349. {
  6350. if( generateCode )
  6351. {
  6352. if( ctx->type.dataType.IsReference() )
  6353. {
  6354. // The pointer on the stack refers to the handle
  6355. ctx->bc.Instr(asBC_ChkRefS);
  6356. }
  6357. else
  6358. {
  6359. // The pointer on the stack refers to the object
  6360. ctx->bc.Instr(asBC_CHKREF);
  6361. }
  6362. }
  6363. ctx->type.dataType.MakeHandle(false);
  6364. }
  6365. // A const object can be converted to a non-const object through a copy
  6366. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  6367. allowObjectConstruct )
  6368. {
  6369. // Does the object type allow a copy to be made?
  6370. if( ctx->type.dataType.CanBeCopied() )
  6371. {
  6372. if( generateCode )
  6373. {
  6374. // Make a temporary object with the copy
  6375. PrepareTemporaryVariable(node, ctx);
  6376. }
  6377. // In case the object was already in a temporary variable, then the function
  6378. // didn't really do anything so we need to remove the constness here
  6379. ctx->type.dataType.MakeReadOnly(false);
  6380. // Add the cost for the copy
  6381. cost += asCC_TO_OBJECT_CONV;
  6382. }
  6383. }
  6384. if( ctx->type.dataType.IsReference() )
  6385. {
  6386. // This may look strange, but a value type allocated on the stack is already
  6387. // correct, so nothing should be done other than remove the mark as reference.
  6388. // For types allocated on the heap, it is necessary to dereference the pointer
  6389. // that is currently on the stack
  6390. if( IsVariableOnHeap(ctx->type.stackOffset) )
  6391. Dereference(ctx, generateCode);
  6392. else
  6393. ctx->type.dataType.MakeReference(false);
  6394. }
  6395. // A non-const object can be converted to a const object directly
  6396. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6397. {
  6398. ctx->type.dataType.MakeReadOnly(true);
  6399. }
  6400. }
  6401. else // if( to.IsReference() )
  6402. {
  6403. // reference to handle -> reference
  6404. // handle -> reference
  6405. // object -> reference
  6406. if( ctx->type.dataType.IsReference() )
  6407. {
  6408. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6409. {
  6410. // ASHANDLE objects are really value types, so explicit handle can be removed
  6411. ctx->type.isExplicitHandle = false;
  6412. ctx->type.dataType.MakeHandle(false);
  6413. }
  6414. // A reference to a handle can be converted to a reference to an object
  6415. // by first reading the address, then verifying that it is not null
  6416. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6417. {
  6418. ctx->type.dataType.MakeHandle(false);
  6419. if( generateCode )
  6420. ctx->bc.Instr(asBC_ChkRefS);
  6421. }
  6422. // A reference to a non-const can be converted to a reference to a const
  6423. if( to.IsReadOnly() )
  6424. ctx->type.dataType.MakeReadOnly(true);
  6425. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6426. {
  6427. // A reference to a const can be converted to a reference to a
  6428. // non-const by copying the object to a temporary variable
  6429. ctx->type.dataType.MakeReadOnly(false);
  6430. if( generateCode )
  6431. {
  6432. // If the object already is a temporary variable, then the copy
  6433. // doesn't have to be made as it is already a unique object
  6434. PrepareTemporaryVariable(node, ctx);
  6435. }
  6436. // Add the cost for the copy
  6437. cost += asCC_TO_OBJECT_CONV;
  6438. }
  6439. }
  6440. else // if( !ctx->type.dataType.IsReference() )
  6441. {
  6442. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6443. if( ctx->type.dataType.IsObjectHandle() )
  6444. {
  6445. bool readOnly = false;
  6446. if( ctx->type.dataType.IsHandleToConst() )
  6447. readOnly = true;
  6448. if( generateCode )
  6449. {
  6450. if( ctx->type.isVariable )
  6451. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  6452. else
  6453. ctx->bc.Instr(asBC_CHKREF);
  6454. }
  6455. ctx->type.dataType.MakeHandle(false);
  6456. ctx->type.dataType.MakeReference(true);
  6457. // Make sure a handle to const isn't converted to non-const reference
  6458. if( readOnly )
  6459. ctx->type.dataType.MakeReadOnly(true);
  6460. }
  6461. else
  6462. {
  6463. // A value type allocated on the stack is differentiated
  6464. // by it not being a reference. But it can be handled as
  6465. // reference by pushing the pointer on the stack
  6466. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6467. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6468. !IsVariableOnHeap(ctx->type.stackOffset) )
  6469. {
  6470. // Actually the pointer is already pushed on the stack in
  6471. // CompileVariableAccess, so we don't need to do anything else
  6472. }
  6473. else if( generateCode )
  6474. {
  6475. // A non-reference can be converted to a reference,
  6476. // by putting the value in a temporary variable
  6477. // If the input type is read-only we'll need to temporarily
  6478. // remove this constness, otherwise the assignment will fail
  6479. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6480. ctx->type.dataType.MakeReadOnly(false);
  6481. // If the object already is a temporary variable, then the copy
  6482. // doesn't have to be made as it is already a unique object
  6483. PrepareTemporaryVariable(node, ctx);
  6484. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6485. // Add the cost for the copy
  6486. cost += asCC_TO_OBJECT_CONV;
  6487. }
  6488. // This may look strange as the conversion was to make the expression a reference
  6489. // but a value type allocated on the stack is a reference even without the type
  6490. // being marked as such.
  6491. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6492. }
  6493. if (to.IsReadOnly())
  6494. {
  6495. // This doesn't cost anything
  6496. ctx->type.dataType.MakeReadOnly(true);
  6497. }
  6498. if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
  6499. {
  6500. // A const object can be converted to a non-const object through a copy
  6501. if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
  6502. {
  6503. ctx->type.dataType.MakeReadOnly(false);
  6504. if (generateCode)
  6505. {
  6506. // Make a temporary copy of the object in order to make it non-const
  6507. PrepareTemporaryVariable(node, ctx);
  6508. }
  6509. // Add the cost for the copy
  6510. cost += asCC_TO_OBJECT_CONV;
  6511. }
  6512. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6513. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6514. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6515. {
  6516. if (generateCode)
  6517. PrepareTemporaryVariable(node, ctx);
  6518. else
  6519. {
  6520. ctx->type.dataType.MakeReadOnly(false);
  6521. ctx->type.isConstant = false;
  6522. }
  6523. // Add the cost for the copy
  6524. cost += asCC_TO_OBJECT_CONV;
  6525. }
  6526. }
  6527. }
  6528. }
  6529. }
  6530. return cost;
  6531. }
  6532. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct)
  6533. {
  6534. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6535. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6536. if( !objType )
  6537. return asCC_NO_CONV;
  6538. asCArray<int> funcs;
  6539. if (objType->flags & asOBJ_VALUE)
  6540. {
  6541. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6542. for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++)
  6543. {
  6544. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6545. if (func->parameterTypes.GetLength() == 1 &&
  6546. func->parameterTypes[0].IsPrimitive() &&
  6547. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6548. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) )
  6549. {
  6550. funcs.PushLast(func->id);
  6551. }
  6552. }
  6553. }
  6554. else if (objType->flags & asOBJ_REF)
  6555. {
  6556. // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference
  6557. for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++)
  6558. {
  6559. asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]];
  6560. if (func->parameterTypes.GetLength() == 1 &&
  6561. func->parameterTypes[0].IsPrimitive() &&
  6562. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6563. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()))
  6564. {
  6565. funcs.PushLast(func->id);
  6566. }
  6567. }
  6568. }
  6569. if( funcs.GetLength() == 0 )
  6570. return asCC_NO_CONV;
  6571. // Check if it is possible to choose a best match
  6572. asCExprContext arg(engine);
  6573. arg.type = ctx->type;
  6574. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6575. asCArray<asCExprContext*> args;
  6576. args.PushLast(&arg);
  6577. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6578. if( funcs.GetLength() != 1 )
  6579. return asCC_NO_CONV;
  6580. if( !generateCode )
  6581. {
  6582. ctx->type.Set(to);
  6583. return cost;
  6584. }
  6585. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6586. // Clear the type of ctx, as the type is moved to the arg
  6587. ctx->type.SetDummy();
  6588. // Value types and script types are allocated through the constructor
  6589. asCExprValue tempObj;
  6590. bool onHeap = false;
  6591. if (!(objType->flags & asOBJ_REF))
  6592. {
  6593. tempObj.dataType = to;
  6594. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6595. tempObj.dataType.MakeReference(true);
  6596. tempObj.isTemporary = true;
  6597. tempObj.isVariable = true;
  6598. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6599. // Push the address of the object on the stack
  6600. if (onHeap)
  6601. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6602. }
  6603. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6604. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6605. if( !(objType->flags & asOBJ_REF) )
  6606. {
  6607. // If the object is allocated on the stack, then call the constructor as a normal function
  6608. if( onHeap )
  6609. {
  6610. int offset = 0;
  6611. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6612. for( asUINT n = 0; n < args.GetLength(); n++ )
  6613. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6614. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6615. }
  6616. else
  6617. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6618. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6619. // Add tag that the object has been initialized
  6620. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6621. // The constructor doesn't return anything,
  6622. // so we have to manually inform the type of
  6623. // the return value
  6624. ctx->type = tempObj;
  6625. if( !onHeap )
  6626. ctx->type.dataType.MakeReference(false);
  6627. // Push the address of the object on the stack again
  6628. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6629. }
  6630. else
  6631. {
  6632. // Call the factory to create the reference type
  6633. PerformFunctionCall(funcs[0], ctx, false, &args);
  6634. // Make another pass to make sure the result has the correct handle and reference settings
  6635. ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct);
  6636. }
  6637. return cost;
  6638. }
  6639. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6640. {
  6641. asASSERT(from->type.isConstant);
  6642. // TODO: node should be the node of the value that is
  6643. // converted (not the operator that provokes the implicit
  6644. // conversion)
  6645. // If the base type is correct there is no more to do
  6646. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6647. // References cannot be constants
  6648. if( from->type.dataType.IsReference() ) return;
  6649. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6650. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6651. {
  6652. if( from->type.dataType.IsFloatType() ||
  6653. from->type.dataType.IsDoubleType() ||
  6654. from->type.dataType.IsUnsignedType() ||
  6655. from->type.dataType.IsIntegerType() )
  6656. {
  6657. asCDataType targetDt;
  6658. if (to.IsEnumType())
  6659. targetDt = to;
  6660. else
  6661. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6662. // Transform the value
  6663. // Float constants can be implicitly converted to int
  6664. if( from->type.dataType.IsFloatType() )
  6665. {
  6666. float fc = from->type.GetConstantF();
  6667. int ic = int(fc);
  6668. if( float(ic) != fc )
  6669. {
  6670. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6671. }
  6672. from->type.SetConstantDW(targetDt, ic);
  6673. }
  6674. // Double constants can be implicitly converted to int
  6675. else if( from->type.dataType.IsDoubleType() )
  6676. {
  6677. double fc = from->type.GetConstantD();
  6678. int ic = int(fc);
  6679. if( double(ic) != fc )
  6680. {
  6681. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6682. }
  6683. from->type.SetConstantDW(targetDt, ic);
  6684. }
  6685. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6686. {
  6687. // Verify that it is possible to convert to signed without getting negative
  6688. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6689. int(from->type.GetConstantDW()) < 0 &&
  6690. convType != asIC_EXPLICIT_VAL_CAST &&
  6691. node != 0 )
  6692. Warning(TXT_CHANGE_SIGN, node);
  6693. // Convert to 32bit
  6694. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6695. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6696. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6697. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6698. else
  6699. from->type.dataType = targetDt;
  6700. }
  6701. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6702. {
  6703. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6704. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6705. // Convert to 32bit
  6706. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6707. }
  6708. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6709. {
  6710. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6711. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6712. // Convert to 32bit
  6713. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6714. }
  6715. else if (from->type.dataType.IsIntegerType() &&
  6716. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6717. {
  6718. // Convert to 32bit
  6719. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6720. from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
  6721. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6722. from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
  6723. }
  6724. else
  6725. {
  6726. // Only int32 and enums should come here and as these are 32bit
  6727. // already nothing needs to be done except set the target type
  6728. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6729. from->type.dataType.IsEnumType()) &&
  6730. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6731. from->type.dataType = targetDt;
  6732. }
  6733. }
  6734. // Check if a downsize is necessary
  6735. if( to.IsIntegerType() &&
  6736. from->type.dataType.IsIntegerType() &&
  6737. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6738. {
  6739. // Verify if it is possible
  6740. if( to.GetSizeInMemoryBytes() == 1 )
  6741. {
  6742. if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6743. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6744. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
  6745. }
  6746. else if( to.GetSizeInMemoryBytes() == 2 )
  6747. {
  6748. if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6749. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6750. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
  6751. }
  6752. }
  6753. }
  6754. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6755. {
  6756. // Float constants can be implicitly converted to int
  6757. if( from->type.dataType.IsFloatType() )
  6758. {
  6759. float fc = from->type.GetConstantF();
  6760. asINT64 ic = asINT64(fc);
  6761. if( float(ic) != fc )
  6762. {
  6763. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6764. }
  6765. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6766. }
  6767. // Double constants can be implicitly converted to int
  6768. else if( from->type.dataType.IsDoubleType() )
  6769. {
  6770. double fc = from->type.GetConstantD();
  6771. asINT64 ic = asINT64(fc);
  6772. if( double(ic) != fc )
  6773. {
  6774. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6775. }
  6776. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6777. }
  6778. else if( from->type.dataType.IsUnsignedType() )
  6779. {
  6780. // Convert to 64bit
  6781. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6782. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6783. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6784. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6785. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6786. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6787. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6788. {
  6789. if( asINT64(from->type.GetConstantQW()) < 0 )
  6790. {
  6791. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6792. }
  6793. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6794. }
  6795. }
  6796. else if( from->type.dataType.IsIntegerType() )
  6797. {
  6798. // Convert to 64bit
  6799. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6800. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
  6801. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6802. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
  6803. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6804. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6805. }
  6806. }
  6807. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6808. {
  6809. if( from->type.dataType.IsFloatType() )
  6810. {
  6811. float fc = from->type.GetConstantF();
  6812. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6813. // To maintain a consistent behaviour across compilers we convert to int first.
  6814. asUINT uic = asUINT(int(fc));
  6815. if( float(uic) != fc )
  6816. {
  6817. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6818. }
  6819. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6820. // Try once more, in case of a smaller type
  6821. ImplicitConversionConstant(from, to, node, convType);
  6822. }
  6823. else if( from->type.dataType.IsDoubleType() )
  6824. {
  6825. double fc = from->type.GetConstantD();
  6826. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6827. // To maintain a consistent behaviour across compilers we convert to int first.
  6828. asUINT uic = asUINT(int(fc));
  6829. if( double(uic) != fc )
  6830. {
  6831. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6832. }
  6833. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6834. // Try once more, in case of a smaller type
  6835. ImplicitConversionConstant(from, to, node, convType);
  6836. }
  6837. else if( from->type.dataType.IsIntegerType() )
  6838. {
  6839. // Verify that it is possible to convert to unsigned without loosing negative
  6840. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6841. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6842. (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
  6843. (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
  6844. {
  6845. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6846. }
  6847. // Check if any data is lost
  6848. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6849. {
  6850. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6851. }
  6852. // Convert to 32bit
  6853. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6854. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
  6855. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6856. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
  6857. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6858. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6859. else
  6860. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6861. // Try once more, in case of a smaller type
  6862. ImplicitConversionConstant(from, to, node, convType);
  6863. }
  6864. else if( from->type.dataType.IsUnsignedType() &&
  6865. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6866. {
  6867. // Convert to 32bit
  6868. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6869. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6870. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6871. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6872. // Try once more, in case of a smaller type
  6873. ImplicitConversionConstant(from, to, node, convType);
  6874. }
  6875. else if( from->type.dataType.IsUnsignedType() &&
  6876. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6877. {
  6878. // Verify if it is possible
  6879. if( to.GetSizeInMemoryBytes() == 1 )
  6880. {
  6881. if( (from->type.dataType.GetSizeInMemoryBytes() == 2 && asBYTE(from->type.GetConstantW()) != from->type.GetConstantW()) ||
  6882. (from->type.dataType.GetSizeInMemoryBytes() == 4 && asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6883. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asBYTE(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6884. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6885. if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6886. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantW()));
  6887. else if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6888. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6889. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6890. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantQW()));
  6891. }
  6892. else if( to.GetSizeInMemoryBytes() == 2 )
  6893. {
  6894. if( (from->type.dataType.GetSizeInMemoryBytes() == 4 && asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6895. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6896. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6897. if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6898. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6899. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6900. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantQW()));
  6901. }
  6902. else if (to.GetSizeInMemoryBytes() == 4)
  6903. {
  6904. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6905. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6906. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6907. }
  6908. }
  6909. }
  6910. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6911. {
  6912. if( from->type.dataType.IsFloatType() )
  6913. {
  6914. float fc = from->type.GetConstantF();
  6915. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6916. asQWORD uic = asQWORD(asINT64(fc));
  6917. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6918. // MSVC6 doesn't support this conversion
  6919. if( float(uic) != fc )
  6920. {
  6921. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6922. }
  6923. #endif
  6924. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6925. }
  6926. else if( from->type.dataType.IsDoubleType() )
  6927. {
  6928. double fc = from->type.GetConstantD();
  6929. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6930. asQWORD uic = asQWORD(asINT64(fc));
  6931. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6932. // MSVC6 doesn't support this conversion
  6933. if( double(uic) != fc )
  6934. {
  6935. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6936. }
  6937. #endif
  6938. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6939. }
  6940. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6941. {
  6942. // Convert to 64bit
  6943. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6944. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
  6945. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6946. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
  6947. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6948. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  6949. // Verify that it is possible to convert to unsigned without loosing negative
  6950. if( asINT64(from->type.GetConstantQW()) < 0 )
  6951. {
  6952. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6953. }
  6954. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6955. }
  6956. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6957. {
  6958. // Verify that it is possible to convert to unsigned without loosing negative
  6959. if( asINT64(from->type.GetConstantQW()) < 0 )
  6960. {
  6961. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6962. }
  6963. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6964. }
  6965. else if( from->type.dataType.IsUnsignedType() )
  6966. {
  6967. // Convert to 64bit
  6968. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6969. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  6970. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6971. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  6972. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6973. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  6974. }
  6975. }
  6976. else if( to.IsFloatType() )
  6977. {
  6978. if( from->type.dataType.IsDoubleType() )
  6979. {
  6980. double ic = from->type.GetConstantD();
  6981. float fc = float(ic);
  6982. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6983. }
  6984. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6985. {
  6986. // Must properly convert value in case the from value is smaller
  6987. int ic;
  6988. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6989. ic = (asINT8)from->type.GetConstantB();
  6990. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6991. ic = (asINT16)from->type.GetConstantW();
  6992. else
  6993. ic = (int)from->type.GetConstantDW();
  6994. float fc = float(ic);
  6995. if( int(fc) != ic )
  6996. {
  6997. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6998. }
  6999. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7000. }
  7001. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7002. {
  7003. float fc = float(asINT64(from->type.GetConstantQW()));
  7004. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7005. {
  7006. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7007. }
  7008. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7009. }
  7010. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7011. {
  7012. // Must properly convert value in case the from value is smaller
  7013. unsigned int uic;
  7014. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7015. uic = from->type.GetConstantB();
  7016. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7017. uic = from->type.GetConstantW();
  7018. else
  7019. uic = from->type.GetConstantDW();
  7020. float fc = float(uic);
  7021. if( (unsigned int)(fc) != uic )
  7022. {
  7023. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7024. }
  7025. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7026. }
  7027. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7028. {
  7029. float fc = float((asINT64)from->type.GetConstantQW());
  7030. if( asQWORD(fc) != from->type.GetConstantQW())
  7031. {
  7032. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7033. }
  7034. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7035. }
  7036. }
  7037. else if( to.IsDoubleType() )
  7038. {
  7039. if( from->type.dataType.IsFloatType() )
  7040. {
  7041. float ic = from->type.GetConstantF();
  7042. double fc = double(ic);
  7043. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7044. }
  7045. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7046. {
  7047. // Must properly convert value in case the from value is smaller
  7048. int ic;
  7049. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7050. ic = (asINT8)from->type.GetConstantB();
  7051. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7052. ic = (asINT16)from->type.GetConstantW();
  7053. else
  7054. ic = (int)from->type.GetConstantDW();
  7055. double fc = double(ic);
  7056. if( int(fc) != ic )
  7057. {
  7058. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7059. }
  7060. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7061. }
  7062. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7063. {
  7064. double fc = double(asINT64(from->type.GetConstantQW()));
  7065. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7066. {
  7067. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7068. }
  7069. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7070. }
  7071. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7072. {
  7073. // Must properly convert value in case the from value is smaller
  7074. unsigned int uic;
  7075. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7076. uic = from->type.GetConstantB();
  7077. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7078. uic = from->type.GetConstantW();
  7079. else
  7080. uic = from->type.GetConstantDW();
  7081. double fc = double(uic);
  7082. if( (unsigned int)(fc) != uic )
  7083. {
  7084. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7085. }
  7086. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7087. }
  7088. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7089. {
  7090. double fc = double((asINT64)from->type.GetConstantQW());
  7091. if( asQWORD(fc) != from->type.GetConstantQW())
  7092. {
  7093. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7094. }
  7095. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7096. }
  7097. }
  7098. }
  7099. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  7100. {
  7101. // Don't allow any operators on expressions that take address of class method
  7102. // If methodName is set but the type is not an object, then it is a global function
  7103. if( lctx->methodName != "" || rctx->IsClassMethod() )
  7104. {
  7105. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  7106. return -1;
  7107. }
  7108. // Implicit handle types should always be treated as handles in assignments
  7109. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  7110. {
  7111. lctx->type.dataType.MakeHandle(true);
  7112. lctx->type.isExplicitHandle = true;
  7113. }
  7114. // If the left hand expression is a property accessor, then that should be used
  7115. // to do the assignment instead of the ordinary operator. The exception is when
  7116. // the property accessor is for a handle property, and the operation is a value
  7117. // assignment.
  7118. if( (lctx->property_get || lctx->property_set) &&
  7119. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  7120. {
  7121. if( op != ttAssignment )
  7122. {
  7123. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  7124. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  7125. }
  7126. // It is not allowed to do a handle assignment on a property
  7127. // accessor that doesn't take a handle in the set accessor.
  7128. if( lctx->property_set && lctx->type.isExplicitHandle )
  7129. {
  7130. // set_opIndex has 2 arguments, where as normal setters have only 1
  7131. asCArray<asCDataType>& parameterTypes =
  7132. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  7133. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  7134. {
  7135. // Process the property to free the memory
  7136. ProcessPropertySetAccessor(lctx, rctx, opNode);
  7137. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  7138. return -1;
  7139. }
  7140. }
  7141. MergeExprBytecodeAndType(ctx, lctx);
  7142. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  7143. }
  7144. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7145. {
  7146. // Get the handle to the object that will be used for the value assignment
  7147. if( ProcessPropertyGetAccessor(lctx, opNode) < 0 )
  7148. return -1;
  7149. }
  7150. if( lctx->type.dataType.IsPrimitive() )
  7151. {
  7152. if( !lctx->type.isLValue )
  7153. {
  7154. Error(TXT_NOT_LVALUE, lexpr);
  7155. return -1;
  7156. }
  7157. if( op != ttAssignment )
  7158. {
  7159. // Compute the operator before the assignment
  7160. asCExprValue lvalue = lctx->type;
  7161. if( lctx->type.isTemporary && !lctx->type.isVariable )
  7162. {
  7163. // The temporary variable must not be freed until the
  7164. // assignment has been performed. lvalue still holds
  7165. // the information about the temporary variable
  7166. lctx->type.isTemporary = false;
  7167. }
  7168. asCExprContext o(engine);
  7169. CompileOperator(opNode, lctx, rctx, &o);
  7170. MergeExprBytecode(rctx, &o);
  7171. rctx->type = o.type;
  7172. // Convert the rvalue to the right type and validate it
  7173. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  7174. MergeExprBytecode(ctx, rctx);
  7175. lctx->type = lvalue;
  7176. // The lvalue continues the same, either it was a variable, or a reference in the register
  7177. }
  7178. else
  7179. {
  7180. // Convert the rvalue to the right type and validate it
  7181. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  7182. MergeExprBytecode(ctx, rctx);
  7183. MergeExprBytecode(ctx, lctx);
  7184. }
  7185. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7186. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7187. ctx->type = lctx->type;
  7188. }
  7189. else if( lctx->type.isExplicitHandle )
  7190. {
  7191. if( !lctx->type.isLValue )
  7192. {
  7193. Error(TXT_NOT_LVALUE, lexpr);
  7194. return -1;
  7195. }
  7196. // Object handles don't have any compound assignment operators
  7197. if( op != ttAssignment )
  7198. {
  7199. asCString str;
  7200. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7201. Error(str, lexpr);
  7202. return -1;
  7203. }
  7204. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  7205. {
  7206. // The object is a value type but that should be treated as a handle
  7207. // Make sure the right hand value is a handle
  7208. if( !rctx->type.isExplicitHandle &&
  7209. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  7210. {
  7211. // Function names can be considered handles already
  7212. if( rctx->methodName == "" )
  7213. {
  7214. asCDataType dt = rctx->type.dataType;
  7215. dt.MakeHandle(true);
  7216. dt.MakeReference(false);
  7217. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  7218. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7219. {
  7220. asCString str;
  7221. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7222. Error(str, rexpr);
  7223. return -1;
  7224. }
  7225. }
  7226. if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles())
  7227. {
  7228. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr);
  7229. return -1;
  7230. }
  7231. // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
  7232. // the code for moving the argument to the stack may not know to correctly handle the argument type
  7233. // in case of variable parameter type.
  7234. rctx->type.isExplicitHandle = true;
  7235. }
  7236. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  7237. {
  7238. // An overloaded assignment operator was found (or a compilation error occured)
  7239. return 0;
  7240. }
  7241. // The object must implement the opAssign method
  7242. asCString msg;
  7243. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7244. Error(msg.AddressOf(), opNode);
  7245. return -1;
  7246. }
  7247. else
  7248. {
  7249. asCDataType dt = lctx->type.dataType;
  7250. dt.MakeReference(false);
  7251. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
  7252. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7253. {
  7254. asCString str;
  7255. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7256. Error(str, rexpr);
  7257. return -1;
  7258. }
  7259. MergeExprBytecode(ctx, rctx);
  7260. MergeExprBytecode(ctx, lctx);
  7261. if(!rctx->type.isRefSafe)
  7262. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7263. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7264. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7265. ctx->type = lctx->type;
  7266. // After the handle assignment the original handle is left on the stack
  7267. ctx->type.dataType.MakeReference(false);
  7268. }
  7269. }
  7270. else // if( lctx->type.dataType.IsObject() )
  7271. {
  7272. // The lvalue reference may be marked as a temporary, if for example
  7273. // it was originated as a handle returned from a function. In such
  7274. // cases it must be possible to assign values to it anyway.
  7275. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7276. {
  7277. // Convert the handle to a object reference
  7278. asCDataType to;
  7279. to = lctx->type.dataType;
  7280. to.MakeHandle(false);
  7281. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  7282. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  7283. }
  7284. // Check for overloaded assignment operator
  7285. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  7286. {
  7287. // An overloaded assignment operator was found (or a compilation error occured)
  7288. return 0;
  7289. }
  7290. // No registered operator was found. In case the operation is a direct
  7291. // assignment and the rvalue is the same type as the lvalue, then we can
  7292. // still use the byte-for-byte copy to do the assignment
  7293. if( op != ttAssignment )
  7294. {
  7295. asCString str;
  7296. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7297. Error(str, lexpr);
  7298. return -1;
  7299. }
  7300. // If the left hand expression is simple, i.e. without any
  7301. // function calls or allocations of memory, then we can avoid
  7302. // doing a copy of the right hand expression (done by PrepareArgument).
  7303. // Instead the reference to the value can be placed directly on the
  7304. // stack.
  7305. //
  7306. // This optimization should only be done for value types, where
  7307. // the application developer is responsible for making the
  7308. // implementation safe against unwanted destruction of the input
  7309. // reference before the time.
  7310. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  7311. // Implicitly convert the rvalue to the type of the lvalue
  7312. bool needConversion = false;
  7313. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7314. needConversion = true;
  7315. if( !simpleExpr || needConversion )
  7316. {
  7317. if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle &&
  7318. !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  7319. {
  7320. // Make the conversion from handle to non-handle without creating
  7321. // a copy of the object (otherwise done by PrepareArgument)
  7322. asCDataType dt = rctx->type.dataType;
  7323. dt.MakeHandle(false);
  7324. ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV);
  7325. needConversion = false;
  7326. }
  7327. asCDataType dt = lctx->type.dataType;
  7328. dt.MakeReference(true);
  7329. // A funcdef can be accessed by ref, but only as read-only
  7330. if( dt.IsFuncdef() && !dt.IsObjectHandle() )
  7331. dt.MakeReadOnly(true);
  7332. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  7333. if( r < 0 )
  7334. return -1;
  7335. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7336. {
  7337. asCString str;
  7338. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7339. Error(str, rexpr);
  7340. return -1;
  7341. }
  7342. }
  7343. else
  7344. {
  7345. // Process any property accessor first, before placing the final reference on the stack
  7346. if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 )
  7347. return -1;
  7348. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  7349. rctx->bc.Instr(asBC_RDSPtr);
  7350. }
  7351. MergeExprBytecode(ctx, rctx);
  7352. MergeExprBytecode(ctx, lctx);
  7353. if( !simpleExpr || needConversion )
  7354. {
  7355. if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) )
  7356. {
  7357. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  7358. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  7359. // as the value allocated on the stack is guaranteed to be safe.
  7360. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  7361. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  7362. else
  7363. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7364. }
  7365. }
  7366. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7367. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7368. ctx->type = lctx->type;
  7369. }
  7370. return 0;
  7371. }
  7372. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  7373. {
  7374. asASSERT(expr->nodeType == snAssignment);
  7375. asCScriptNode *lexpr = expr->firstChild;
  7376. if( lexpr->next )
  7377. {
  7378. // Compile the two expression terms
  7379. asCExprContext lctx(engine), rctx(engine);
  7380. int rr = CompileAssignment(lexpr->next->next, &rctx);
  7381. int lr = CompileCondition(lexpr, &lctx);
  7382. if( lr >= 0 && rr >= 0 )
  7383. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  7384. // Since the operands failed, the assignment was not computed
  7385. ctx->type.SetDummy();
  7386. return -1;
  7387. }
  7388. return CompileCondition(lexpr, ctx);
  7389. }
  7390. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  7391. {
  7392. asCExprValue ctype;
  7393. // Compile the conditional expression
  7394. asCScriptNode *cexpr = expr->firstChild;
  7395. if( cexpr->next )
  7396. {
  7397. //-------------------------------
  7398. // Compile the condition
  7399. asCExprContext e(engine);
  7400. int r = CompileExpression(cexpr, &e);
  7401. if( r < 0 )
  7402. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7403. // Allow value types to be converted to bool using 'bool opImplConv()'
  7404. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  7405. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  7406. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7407. {
  7408. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  7409. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7410. }
  7411. ctype = e.type;
  7412. if( ProcessPropertyGetAccessor(&e, cexpr) < 0)
  7413. return -1;
  7414. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  7415. ProcessDeferredParams(&e);
  7416. //-------------------------------
  7417. // Compile the left expression
  7418. asCExprContext le(engine);
  7419. int lr = CompileAssignment(cexpr->next, &le);
  7420. // Resolve any function names already
  7421. DetermineSingleFunc(&le, cexpr->next);
  7422. //-------------------------------
  7423. // Compile the right expression
  7424. asCExprContext re(engine);
  7425. int rr = CompileAssignment(cexpr->next->next, &re);
  7426. DetermineSingleFunc(&re, cexpr->next->next);
  7427. if (lr >= 0 && rr >= 0)
  7428. {
  7429. // Don't allow any operators on expressions that take address of class method
  7430. if (le.IsClassMethod() || re.IsClassMethod())
  7431. {
  7432. Error(TXT_INVALID_OP_ON_METHOD, expr);
  7433. return -1;
  7434. }
  7435. if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0)
  7436. return -1;
  7437. if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0)
  7438. return -1;
  7439. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  7440. // Allow an anonymous initialization list to be converted to the type in the other condition
  7441. if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
  7442. {
  7443. asCDataType to = re.type.dataType;
  7444. to.MakeReference(false);
  7445. to.MakeReadOnly(false);
  7446. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7447. }
  7448. else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory)
  7449. {
  7450. asCDataType to = le.type.dataType;
  7451. to.MakeReference(false);
  7452. to.MakeReadOnly(false);
  7453. ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7454. }
  7455. if (le.IsAnonymousInitList())
  7456. {
  7457. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
  7458. return -1;
  7459. }
  7460. else if (re.IsAnonymousInitList())
  7461. {
  7462. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next);
  7463. return -1;
  7464. }
  7465. // Try to perform an implicit cast to make the two operands of the same type
  7466. // Choose the conversion that is the least costly
  7467. if (le.type.dataType != re.type.dataType)
  7468. {
  7469. asCExprContext tmp(engine);
  7470. tmp.type = le.type;
  7471. tmp.type.dataType.MakeReference(false);
  7472. asUINT costAtoB = ImplicitConversion(&tmp, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, false);
  7473. if (!tmp.type.dataType.IsEqualExceptRef(re.type.dataType))
  7474. costAtoB = 0xFFFFFFFF;
  7475. tmp.type = re.type;
  7476. tmp.type.dataType.MakeReference(false);
  7477. asUINT costBtoA = ImplicitConversion(&tmp, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, false);
  7478. if (!tmp.type.dataType.IsEqualExceptRef(le.type.dataType))
  7479. costBtoA = 0xFFFFFFFF;
  7480. if (costAtoB < costBtoA && costAtoB != 0xFFFFFFFF)
  7481. {
  7482. Dereference(&le, true);
  7483. ImplicitConversion(&le, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, true);
  7484. }
  7485. else if (costAtoB > costBtoA && costBtoA != 0xFFFFFFFF)
  7486. {
  7487. Dereference(&re, true);
  7488. ImplicitConversion(&re, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, true);
  7489. }
  7490. // If the cost for conversion is the same in both directions we have an ambigious situation,
  7491. // which we do not resolve. In that case the script need to perform an explicit conversion
  7492. }
  7493. // Allow a 0 to be implicitly converted to the other type
  7494. if (le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType())
  7495. {
  7496. asCDataType to = re.type.dataType;
  7497. to.MakeReference(false);
  7498. to.MakeReadOnly(true);
  7499. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7500. }
  7501. else if( re.type.isConstant && re.type.GetConstantData() == 0 && re.type.dataType.IsIntegerType())
  7502. {
  7503. asCDataType to = le.type.dataType;
  7504. to.MakeReference(false);
  7505. to.MakeReadOnly(true);
  7506. ImplicitConversionConstant(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7507. }
  7508. // Allow expression to be converted to handle if the other is handle
  7509. if (!le.type.dataType.IsObjectHandle() && re.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo() )
  7510. {
  7511. asCDataType dt = le.type.dataType;
  7512. dt.MakeHandle(true);
  7513. ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV);
  7514. }
  7515. if (!re.type.dataType.IsObjectHandle() && le.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo())
  7516. {
  7517. asCDataType dt = re.type.dataType;
  7518. dt.MakeHandle(true);
  7519. ImplicitConversion(&re, dt, cexpr->next->next, asIC_IMPLICIT_CONV);
  7520. }
  7521. // Allow either case to be converted to const @ if the other is const @
  7522. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  7523. {
  7524. le.type.dataType.MakeHandleToConst(true);
  7525. re.type.dataType.MakeHandleToConst(true);
  7526. }
  7527. // Make sure both expressions have the same type
  7528. if (!le.type.dataType.IsEqualExceptRefAndConst(re.type.dataType))
  7529. {
  7530. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7531. return -1;
  7532. }
  7533. //---------------------------------
  7534. // Output the byte code
  7535. int afterLabel = nextLabel++;
  7536. int elseLabel = nextLabel++;
  7537. // If left expression is void, then we don't need to store the result
  7538. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  7539. {
  7540. // Put the code for the condition expression on the output
  7541. MergeExprBytecode(ctx, &e);
  7542. // Added the branch decision
  7543. ctx->type = e.type;
  7544. ConvertToVariable(ctx);
  7545. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7546. ctx->bc.Instr(asBC_ClrHi);
  7547. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7548. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7549. // Add the left expression
  7550. MergeExprBytecode(ctx, &le);
  7551. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7552. // Add the right expression
  7553. ctx->bc.Label((short)elseLabel);
  7554. MergeExprBytecode(ctx, &re);
  7555. ctx->bc.Label((short)afterLabel);
  7556. // Set the type of the result
  7557. ctx->type = le.type;
  7558. }
  7559. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7560. {
  7561. // Special case for when both results are 'null'
  7562. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7563. // Put the code for the condition expression on the output
  7564. MergeExprBytecode(ctx, &e);
  7565. // Load the result into the register, but ignore the value since both paths give the same response
  7566. ctx->type = e.type;
  7567. ConvertToVariable(ctx);
  7568. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7569. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7570. // Return a null constant
  7571. ctx->bc.Instr(asBC_PshNull);
  7572. ctx->type.SetNullConstant();
  7573. }
  7574. else
  7575. {
  7576. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7577. //
  7578. // Restrictions for the condition to be used as lvalue:
  7579. // 1. both b and c must be of the same type and be lvalue references
  7580. // 2. neither of the expressions can have any deferred arguments
  7581. // that would have to be cleaned up after the reference
  7582. // 3. neither expression can be temporary
  7583. //
  7584. // If either expression is local, the resulting lvalue is not valid
  7585. // for return since it is not allowed to return references to local
  7586. // variables.
  7587. //
  7588. // The reference to the local variable must be loaded into the register,
  7589. // the resulting expression must not be considered as a local variable
  7590. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7591. if( le.type.isLValue && re.type.isLValue &&
  7592. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() == 0 &&
  7593. !le.type.isTemporary && !re.type.isTemporary &&
  7594. le.type.dataType == re.type.dataType )
  7595. {
  7596. // Put the code for the condition expression on the output
  7597. MergeExprBytecode(ctx, &e);
  7598. // Add the branch decision
  7599. ctx->type = e.type;
  7600. ConvertToVariable(ctx);
  7601. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7602. ctx->bc.Instr(asBC_ClrHi);
  7603. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7604. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7605. // Start of the left expression
  7606. MergeExprBytecode(ctx, &le);
  7607. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7608. {
  7609. // Load the address of the variable into the register
  7610. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  7611. }
  7612. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7613. // Start of the right expression
  7614. ctx->bc.Label((short)elseLabel);
  7615. MergeExprBytecode(ctx, &re);
  7616. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7617. {
  7618. // Load the address of the variable into the register
  7619. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  7620. }
  7621. ctx->bc.Label((short)afterLabel);
  7622. // In case the options were to objects, it is necessary to dereference the pointer on
  7623. // the stack so it will point to the actual object, instead of the variable
  7624. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7625. {
  7626. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7627. ctx->bc.Instr(asBC_RDSPtr);
  7628. }
  7629. // The result is an lvalue
  7630. ctx->type.isLValue = true;
  7631. ctx->type.dataType = le.type.dataType;
  7632. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7633. ctx->type.dataType.MakeReference(true);
  7634. else
  7635. ctx->type.dataType.MakeReference(false);
  7636. // It can't be a treated as a variable, since we don't know which one was used
  7637. ctx->type.isVariable = false;
  7638. ctx->type.isTemporary = false;
  7639. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7640. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7641. }
  7642. else
  7643. {
  7644. // Allocate temporary variable and copy the result to that one
  7645. asCExprValue temp;
  7646. temp = le.type;
  7647. temp.dataType.MakeReference(false);
  7648. temp.dataType.MakeReadOnly(false);
  7649. // Make sure the variable isn't used in any of the expressions,
  7650. // as it would be overwritten which may cause crashes or less visible bugs
  7651. int l = int(reservedVariables.GetLength());
  7652. e.bc.GetVarsUsed(reservedVariables);
  7653. le.bc.GetVarsUsed(reservedVariables);
  7654. re.bc.GetVarsUsed(reservedVariables);
  7655. int offset = AllocateVariable(temp.dataType, true, false);
  7656. reservedVariables.SetLength(l);
  7657. temp.SetVariable(temp.dataType, offset, true);
  7658. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7659. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7660. // Put the code for the condition expression on the output
  7661. MergeExprBytecode(ctx, &e);
  7662. // Add the branch decision
  7663. ctx->type = e.type;
  7664. ConvertToVariable(ctx);
  7665. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7666. ctx->bc.Instr(asBC_ClrHi);
  7667. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7668. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7669. // Assign the result of the left expression to the temporary variable
  7670. asCExprValue rtemp;
  7671. rtemp = temp;
  7672. if( rtemp.dataType.IsObjectHandle() )
  7673. rtemp.isExplicitHandle = true;
  7674. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7675. MergeExprBytecode(ctx, &le);
  7676. if( !rtemp.dataType.IsPrimitive() )
  7677. {
  7678. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7679. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7680. }
  7681. asCExprValue result;
  7682. result = rtemp;
  7683. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7684. if( !result.dataType.IsPrimitive() )
  7685. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7686. // Release the old temporary variable
  7687. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7688. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7689. ProcessDeferredParams(ctx);
  7690. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7691. // Start of the right expression
  7692. ctx->bc.Label((short)elseLabel);
  7693. // Copy the result to the same temporary variable
  7694. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7695. MergeExprBytecode(ctx, &re);
  7696. if( !rtemp.dataType.IsPrimitive() )
  7697. {
  7698. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7699. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7700. }
  7701. result = rtemp;
  7702. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7703. if( !result.dataType.IsPrimitive() )
  7704. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7705. // Release the old temporary variable
  7706. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7707. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7708. ProcessDeferredParams(ctx);
  7709. ctx->bc.Label((short)afterLabel);
  7710. // Set the temporary variable as output
  7711. ctx->type = rtemp;
  7712. ctx->type.isExplicitHandle = isExplicitHandle;
  7713. if( !ctx->type.dataType.IsPrimitive() )
  7714. {
  7715. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7716. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7717. }
  7718. // Make sure the output isn't marked as being a literal constant
  7719. ctx->type.isConstant = false;
  7720. }
  7721. }
  7722. }
  7723. else
  7724. {
  7725. ctx->type.SetDummy();
  7726. return -1;
  7727. }
  7728. }
  7729. else
  7730. return CompileExpression(cexpr, ctx);
  7731. return 0;
  7732. }
  7733. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7734. {
  7735. asASSERT(expr->nodeType == snExpression);
  7736. // Convert to polish post fix, i.e: a+b => ab+
  7737. asCArray<asCScriptNode *> postfix;
  7738. ConvertToPostFix(expr, postfix);
  7739. // Compile the postfix formatted expression
  7740. return CompilePostFixExpression(&postfix, ctx);
  7741. }
  7742. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7743. {
  7744. // The algorithm that I've implemented here is similar to
  7745. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7746. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7747. // Count the nodes in order to preallocate the buffers
  7748. int count = 0;
  7749. asCScriptNode *node = expr->firstChild;
  7750. while( node )
  7751. {
  7752. count++;
  7753. node = node->next;
  7754. }
  7755. asCArray<asCScriptNode *> stackA(count);
  7756. asCArray<asCScriptNode *> &stackB = postfix;
  7757. stackB.Allocate(count, false);
  7758. node = expr->firstChild;
  7759. while( node )
  7760. {
  7761. int precedence = GetPrecedence(node);
  7762. while( stackA.GetLength() > 0 &&
  7763. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7764. stackB.PushLast(stackA.PopLast());
  7765. stackA.PushLast(node);
  7766. node = node->next;
  7767. }
  7768. while( stackA.GetLength() > 0 )
  7769. stackB.PushLast(stackA.PopLast());
  7770. }
  7771. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7772. {
  7773. // Shouldn't send any byte code
  7774. asASSERT(ctx->bc.GetLastInstr() == -1);
  7775. // Set the context to a dummy type to avoid further
  7776. // errors in case the expression fails to compile
  7777. ctx->type.SetDummy();
  7778. // Evaluate the operands and operators
  7779. asCArray<asCExprContext*> free;
  7780. asCArray<asCExprContext*> expr;
  7781. int ret = 0;
  7782. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7783. {
  7784. asCScriptNode *node = (*postfix)[n];
  7785. if( node->nodeType == snExprTerm )
  7786. {
  7787. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7788. expr.PushLast(e);
  7789. e->exprNode = node;
  7790. ret = CompileExpressionTerm(node, e);
  7791. }
  7792. else
  7793. {
  7794. asCExprContext *r = expr.PopLast();
  7795. asCExprContext *l = expr.PopLast();
  7796. // Now compile the operator
  7797. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7798. ret = CompileOperator(node, l, r, e);
  7799. expr.PushLast(e);
  7800. // Free the operands
  7801. l->Clear();
  7802. free.PushLast(l);
  7803. r->Clear();
  7804. free.PushLast(r);
  7805. }
  7806. }
  7807. if( ret == 0 )
  7808. {
  7809. asASSERT(expr.GetLength() == 1);
  7810. // The final result should be moved to the output context
  7811. MergeExprBytecodeAndType(ctx, expr[0]);
  7812. }
  7813. // Clean up
  7814. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7815. asDELETE(expr[e], asCExprContext);
  7816. for( asUINT f = 0; f < free.GetLength(); f++ )
  7817. asDELETE(free[f], asCExprContext);
  7818. return ret;
  7819. }
  7820. int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7821. {
  7822. asASSERT(node->nodeType == snInitList);
  7823. // Do not allow constructing non-shared types in shared functions
  7824. if (outFunc->IsShared() &&
  7825. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7826. {
  7827. asCString msg;
  7828. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7829. Error(msg, node);
  7830. }
  7831. // If this is compiled from a default arg, then use the script code for the default arg
  7832. asCScriptCode *origCode = script;
  7833. if (ctx->origCode)
  7834. script = ctx->origCode;
  7835. // Allocate and initialize the temporary object
  7836. int offset = AllocateVariable(dt, true);
  7837. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7838. // Push the reference to the object on the stack
  7839. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7840. ctx->type.SetVariable(dt, offset, true);
  7841. ctx->type.isLValue = false;
  7842. // If the variable is allocated on the heap we have a reference,
  7843. // otherwise the actual object pointer is pushed on the stack.
  7844. if (IsVariableOnHeap(offset))
  7845. ctx->type.dataType.MakeReference(true);
  7846. // Clear the flag for anonymous initalization list as it is no
  7847. // longer true now that the object has been initialized.
  7848. ctx->isAnonymousInitList = false;
  7849. ctx->origCode = 0;
  7850. script = origCode;
  7851. return 0;
  7852. }
  7853. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7854. {
  7855. // Shouldn't send any byte code
  7856. asASSERT(ctx->bc.GetLastInstr() == -1);
  7857. // Check if this is an initialization of a temp object with an initialization list
  7858. if (node->firstChild )
  7859. {
  7860. if (node->firstChild->nodeType == snDataType)
  7861. {
  7862. // Determine the type of the temporary object
  7863. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7864. return CompileAnonymousInitList(node->lastChild, ctx, dt);
  7865. }
  7866. else if (node->firstChild->nodeType == snInitList)
  7867. {
  7868. // As the type is not yet known, the init list will be compiled at a
  7869. // later time when the type can be determined from the destination
  7870. ctx->SetAnonymousInitList(node->firstChild, script);
  7871. return 0;
  7872. }
  7873. }
  7874. // Set the type as a dummy by default, in case of any compiler errors
  7875. ctx->type.SetDummy();
  7876. // Compile the value node
  7877. asCScriptNode *vnode = node->firstChild;
  7878. while( vnode->nodeType != snExprValue )
  7879. vnode = vnode->next;
  7880. asCExprContext v(engine);
  7881. int r = CompileExpressionValue(vnode, &v);
  7882. if( r < 0 )
  7883. return r;
  7884. // Compile post fix operators
  7885. asCScriptNode *pnode = vnode->next;
  7886. while( pnode )
  7887. {
  7888. r = CompileExpressionPostOp(pnode, &v);
  7889. if( r < 0 )
  7890. return r;
  7891. pnode = pnode->next;
  7892. }
  7893. // Compile pre fix operators
  7894. pnode = vnode->prev;
  7895. while( pnode )
  7896. {
  7897. r = CompileExpressionPreOp(pnode, &v);
  7898. if( r < 0 )
  7899. return r;
  7900. pnode = pnode->prev;
  7901. }
  7902. // Return the byte code and final type description
  7903. MergeExprBytecodeAndType(ctx, &v);
  7904. return 0;
  7905. }
  7906. // returns:
  7907. // SL_LOCALCONST = local constant
  7908. // SL_LOCALVAR = local variable
  7909. // SL_NOMATCH = no match
  7910. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult)
  7911. {
  7912. sVariable *v = 0;
  7913. if (variables)
  7914. v = variables->GetVariable(name.AddressOf());
  7915. if (v)
  7916. {
  7917. if (v->isPureConstant)
  7918. {
  7919. outResult->type.SetConstantData(v->type, v->constantValue);
  7920. return SL_LOCALCONST;
  7921. }
  7922. outResult->type.SetVariable(v->type, v->stackOffset, false);
  7923. return SL_LOCALVAR;
  7924. }
  7925. return SL_NOMATCH;
  7926. }
  7927. // returns:
  7928. // SL_CLASSPROPACCESS = class property accessor
  7929. // SL_CLASSPROP = class property
  7930. // SL_CLASSMETHOD = class method
  7931. // SL_CLASSTYPE = class child type
  7932. // SL_NOMATCH = no match
  7933. // SL_ERROR = error
  7934. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult)
  7935. {
  7936. // See if there are any matching property accessors
  7937. asCExprContext access(engine);
  7938. access.type.Set(asCDataType::CreateType(objType, false));
  7939. access.type.dataType.MakeReference(true);
  7940. int r = 0;
  7941. // Indexed property access
  7942. asCExprContext dummyArg(engine);
  7943. r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true);
  7944. if (r == 0)
  7945. {
  7946. // Normal property access
  7947. r = FindPropertyAccessor(name, &access, 0, 0, true);
  7948. }
  7949. if (r <= -3) return SL_ERROR;
  7950. if (r != 0)
  7951. {
  7952. // The symbol matches getters/setters (though not necessarily a compilable match)
  7953. MergeExprBytecodeAndType(outResult, &access);
  7954. outResult->type.dataType.SetTypeInfo(objType);
  7955. return SL_CLASSPROPACCESS;
  7956. }
  7957. // Look for matching properties
  7958. asCDataType dt;
  7959. dt = asCDataType::CreateType(objType, false);
  7960. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7961. if (prop)
  7962. {
  7963. outResult->type.dataType.SetTypeInfo(objType);
  7964. return SL_CLASSPROP;
  7965. }
  7966. // If it is not a property, it may still be the name of a method
  7967. asCObjectType *ot = objType;
  7968. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  7969. {
  7970. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7971. if (f->name == name &&
  7972. (builder->module->m_accessMask & f->accessMask))
  7973. {
  7974. outResult->type.dataType.SetTypeInfo(objType);
  7975. return SL_CLASSMETHOD;
  7976. }
  7977. }
  7978. // If it is not a method, then it can still be a child type
  7979. for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
  7980. {
  7981. if (ot->childFuncDefs[n]->name == name)
  7982. {
  7983. outResult->type.dataType.SetTypeInfo(objType);
  7984. return SL_CLASSTYPE;
  7985. }
  7986. }
  7987. return SL_NOMATCH;
  7988. }
  7989. // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy
  7990. // The 'outResult' will be used to return info on what was identified, but no code will be produced by this function
  7991. // input:
  7992. // name = the name of the symbol to look for
  7993. // scope = explicit scope informed
  7994. // objType = used to look for symbols within object type (e.g. when compiling post op), in this case no local or global symbols will be looked up
  7995. // returns:
  7996. // SL_NOMATCH = no matching symbol
  7997. // SL_LOCALCONST = local constant
  7998. // SL_LOCALVAR = local variable
  7999. // SL_THISPTR = this pointer
  8000. // SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found
  8001. // SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found
  8002. // SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found
  8003. // SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found
  8004. // SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8005. // SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8006. // SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8007. // SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8008. // SL_GLOBALTYPE = type, lookupResult->dataType holds the type
  8009. // SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8010. // SL_ERROR = error
  8011. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult)
  8012. {
  8013. asASSERT(outResult);
  8014. // It is a local variable or parameter?
  8015. // This is not accessible by default arg expressions
  8016. if (!isCompilingDefaultArg && scope == "" && !objType )
  8017. {
  8018. SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult);
  8019. if (r != 0)
  8020. return r;
  8021. }
  8022. // Is it a class member?
  8023. if (scope == "" && ((objType) || (outFunc && outFunc->objectType)))
  8024. {
  8025. // 'this' is not accessible by default arg expressions
  8026. if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg)
  8027. {
  8028. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8029. // The object pointer is located at stack position 0
  8030. outResult->type.SetVariable(dt, 0, false);
  8031. return SL_THISPTR;
  8032. }
  8033. // 'super' is not accessible by default arg expressions
  8034. if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg)
  8035. {
  8036. // If the class is derived from another class, then super can be used to call the base' class constructor
  8037. if (outFunc && outFunc->objectType->derivedFrom)
  8038. {
  8039. outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom);
  8040. return SL_CLASSMETHOD;
  8041. }
  8042. }
  8043. // Look for members in the type
  8044. // class members are only accessible in default arg expressions as post op '.'
  8045. if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) )
  8046. {
  8047. SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult);
  8048. if (r != 0)
  8049. return r;
  8050. }
  8051. }
  8052. // Recursively search parent namespaces for global entities
  8053. asSNameSpace *currNamespace = DetermineNameSpace("");
  8054. while( !objType && currNamespace )
  8055. {
  8056. asCString currScope = scope;
  8057. // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
  8058. // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
  8059. int n = currScope.FindLast("::");
  8060. asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
  8061. asCString nsName = n >= 0 ? currScope.SubString(0, n) : asCString("");
  8062. // If the scope represents a type that the current class inherits
  8063. // from then that should be used instead of going through the namespaces
  8064. if (nsName == "" && (outFunc && outFunc->objectType))
  8065. {
  8066. asCObjectType *ot = outFunc->objectType;
  8067. while (ot)
  8068. {
  8069. if (ot->name == typeName)
  8070. {
  8071. SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult);
  8072. if (r != 0)
  8073. return r;
  8074. }
  8075. ot = ot->derivedFrom;
  8076. }
  8077. }
  8078. // If the scope starts with :: then search from the global scope
  8079. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8080. {
  8081. if (nsName != "")
  8082. {
  8083. if (currNamespace->name != "")
  8084. nsName = currNamespace->name + "::" + nsName;
  8085. }
  8086. else
  8087. nsName = currNamespace->name;
  8088. }
  8089. else
  8090. nsName = nsName.SubString(2);
  8091. // Get the namespace for this scope
  8092. asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf());
  8093. if (ns)
  8094. {
  8095. // Is there a type with typeName in the namespace?
  8096. asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0);
  8097. // Check if the symbol is a member of that type
  8098. if (scopeType)
  8099. {
  8100. // Is it an object type?
  8101. if (CastToObjectType(scopeType))
  8102. {
  8103. SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult);
  8104. if (r != 0)
  8105. return r;
  8106. }
  8107. // Is it an enum type?
  8108. if (CastToEnumType(scopeType))
  8109. {
  8110. asDWORD value = 0;
  8111. asCDataType dt;
  8112. if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value))
  8113. {
  8114. // an enum value was resolved
  8115. outResult->type.SetConstantDW(dt, value);
  8116. outResult->symbolNamespace = ns;
  8117. return SL_ENUMVAL;
  8118. }
  8119. }
  8120. }
  8121. }
  8122. // Get the namespace for this scope. This may return null if the scope is an enum
  8123. nsName = currScope;
  8124. // If the scope starts with :: then search from the global scope
  8125. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8126. {
  8127. if (nsName != "")
  8128. {
  8129. if (currNamespace->name != "")
  8130. nsName = currNamespace->name + "::" + nsName;
  8131. }
  8132. else
  8133. nsName = currNamespace->name;
  8134. }
  8135. else
  8136. nsName = nsName.SubString(2);
  8137. ns = engine->FindNameSpace(nsName.AddressOf());
  8138. // Is it a global property?
  8139. if (ns)
  8140. {
  8141. // See if there are any matching global property accessors
  8142. asCExprContext access(engine);
  8143. int r = 0;
  8144. // Indexed property access
  8145. asCExprContext dummyArg(engine);
  8146. r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns);
  8147. if (r == 0)
  8148. {
  8149. // Normal property access
  8150. r = FindPropertyAccessor(name, &access, 0, ns);
  8151. }
  8152. if (r <= -3) return SL_ERROR;
  8153. if (r != 0)
  8154. {
  8155. // The symbol matches getters/setters (though not necessarily a compilable match)
  8156. MergeExprBytecodeAndType(outResult, &access);
  8157. outResult->symbolNamespace = ns;
  8158. return SL_GLOBALPROPACCESS;
  8159. }
  8160. // See if there is any matching global property
  8161. bool isCompiled = true;
  8162. bool isPureConstant = false;
  8163. bool isAppProp = false;
  8164. asQWORD constantValue = 0;
  8165. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8166. if (prop)
  8167. {
  8168. // If the global property is a pure constant
  8169. // we can allow the compiler to optimize it. Pure
  8170. // constants are global constant variables that were
  8171. // initialized by literal constants.
  8172. if (isPureConstant)
  8173. {
  8174. outResult->type.SetConstantData(prop->type, constantValue);
  8175. outResult->symbolNamespace = ns;
  8176. return SL_GLOBALCONST;
  8177. }
  8178. else
  8179. {
  8180. outResult->type.Set(prop->type);
  8181. outResult->symbolNamespace = ns;
  8182. return SL_GLOBALVAR;
  8183. }
  8184. }
  8185. }
  8186. // Is it the name of a global function?
  8187. if (ns)
  8188. {
  8189. asCArray<int> funcs;
  8190. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8191. if (funcs.GetLength() > 0)
  8192. {
  8193. // Defer the evaluation of which function until it is actually used
  8194. // Store the namespace and name of the function for later
  8195. outResult->type.SetUndefinedFuncHandle(engine);
  8196. outResult->methodName = ns ? ns->name + "::" + name : name;
  8197. outResult->symbolNamespace = ns;
  8198. return SL_GLOBALFUNC;
  8199. }
  8200. }
  8201. // Check for type names
  8202. if (ns)
  8203. {
  8204. asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0);
  8205. if (type)
  8206. {
  8207. outResult->type.dataType = asCDataType::CreateType(type, false);
  8208. return SL_GLOBALTYPE;
  8209. }
  8210. }
  8211. // Is it an enum value?
  8212. if (ns && !engine->ep.requireEnumScope)
  8213. {
  8214. // Look for the enum value without explicitly informing the enum type
  8215. asDWORD value = 0;
  8216. asCDataType dt;
  8217. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  8218. if (e)
  8219. {
  8220. if (e == 2)
  8221. {
  8222. // Ambiguous enum value: Save the name for resolution later.
  8223. // The ambiguity could be resolved now, but I hesitate
  8224. // to store too much information in the context.
  8225. outResult->enumValue = name.AddressOf();
  8226. // We cannot set a dummy value because it will pass through
  8227. // cleanly as an integer.
  8228. outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8229. outResult->symbolNamespace = ns;
  8230. return SL_ENUMVAL;
  8231. }
  8232. else
  8233. {
  8234. // an enum value was resolved
  8235. outResult->type.SetConstantDW(dt, value);
  8236. outResult->symbolNamespace = ns;
  8237. return SL_ENUMVAL;
  8238. }
  8239. }
  8240. }
  8241. // If the given scope starts with '::' then the search starts from global scope
  8242. if (scope.GetLength() >= 2 && scope[0] == ':')
  8243. break;
  8244. // Move up to parent namespace
  8245. currNamespace = engine->GetParentNameSpace(currNamespace);
  8246. }
  8247. // The name doesn't match any symbol
  8248. return SL_NOMATCH;
  8249. }
  8250. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType)
  8251. {
  8252. asCExprContext lookupResult(engine);
  8253. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult);
  8254. if (symbolType < 0)
  8255. {
  8256. // Give dummy value
  8257. ctx->type.SetDummy();
  8258. return -1;
  8259. }
  8260. if (symbolType == SL_NOMATCH)
  8261. {
  8262. // Give dummy value
  8263. ctx->type.SetDummy();
  8264. if (!isOptional)
  8265. {
  8266. // No matching symbol
  8267. asCString msg;
  8268. asCString smbl;
  8269. if (scope == "::")
  8270. smbl = scope;
  8271. else if (scope != "")
  8272. smbl = scope + "::";
  8273. smbl += name;
  8274. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  8275. Error(msg, errNode);
  8276. }
  8277. return -1;
  8278. }
  8279. // It is a local variable or parameter?
  8280. if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR )
  8281. {
  8282. // This is not accessible by default arg expressions
  8283. asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables);
  8284. sVariable *v = variables->GetVariable(name.AddressOf());
  8285. asASSERT(v);
  8286. if( v->isPureConstant )
  8287. ctx->type.SetConstantData(v->type, v->constantValue);
  8288. else if( v->type.IsPrimitive() )
  8289. {
  8290. if( v->type.IsReference() )
  8291. {
  8292. // Copy the reference into the register
  8293. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  8294. ctx->bc.Instr(asBC_PopRPtr);
  8295. ctx->type.Set(v->type);
  8296. }
  8297. else
  8298. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8299. // Set as lvalue unless it is a const variable
  8300. if( !v->type.IsReadOnly() )
  8301. ctx->type.isLValue = true;
  8302. }
  8303. else
  8304. {
  8305. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  8306. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8307. // If the variable is allocated on the heap we have a reference,
  8308. // otherwise the actual object pointer is pushed on the stack.
  8309. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  8310. // Implicitly dereference handle parameters sent by reference
  8311. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  8312. ctx->bc.Instr(asBC_RDSPtr);
  8313. // Mark the object as safe for access unless it is a handle, as the
  8314. // life time of the object is guaranteed throughout the scope.
  8315. if( !v->type.IsObjectHandle() )
  8316. ctx->type.isRefSafe = true;
  8317. // Set as lvalue unless it is a const variable
  8318. if (!v->type.IsReadOnly())
  8319. ctx->type.isLValue = true;
  8320. }
  8321. return 0;
  8322. }
  8323. // Is it a class member?
  8324. if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR)
  8325. {
  8326. // This is not accessible by default arg expressions
  8327. asASSERT(!isCompilingDefaultArg);
  8328. if (symbolType == SL_THISPTR)
  8329. {
  8330. asASSERT(name == THIS_TOKEN && !objType && scope == "");
  8331. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8332. // The object pointer is located at stack position 0
  8333. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8334. ctx->type.SetVariable(dt, 0, false);
  8335. ctx->type.dataType.MakeReference(true);
  8336. ctx->type.isLValue = true;
  8337. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  8338. ctx->type.isRefSafe = true;
  8339. return 0;
  8340. }
  8341. if (symbolType == SL_CLASSPROPACCESS)
  8342. {
  8343. if (scope != "")
  8344. {
  8345. // Cannot access non-static members like this
  8346. asCString msg;
  8347. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8348. Error(msg, errNode);
  8349. return -1;
  8350. }
  8351. // See if there are any matching property accessors
  8352. asCExprContext access(engine);
  8353. if (objType)
  8354. access.type.Set(asCDataType::CreateType(objType, false));
  8355. else
  8356. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
  8357. access.type.dataType.MakeReference(true);
  8358. int r = 0;
  8359. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8360. {
  8361. // This is an index access, check if there is a property accessor that takes an index arg
  8362. asCExprContext dummyArg(engine);
  8363. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  8364. }
  8365. if (r == 0)
  8366. {
  8367. // Normal property access
  8368. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  8369. }
  8370. if (r < 0) return -1;
  8371. if (access.property_get == 0 && access.property_set == 0)
  8372. {
  8373. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8374. asCString msg;
  8375. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8376. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8377. else
  8378. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8379. Error(msg, errNode);
  8380. return -1;
  8381. }
  8382. if (!objType)
  8383. {
  8384. // Prepare the bytecode for the member access
  8385. // This is only done when accessing through the implicit this pointer
  8386. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8387. }
  8388. MergeExprBytecodeAndType(ctx, &access);
  8389. return 0;
  8390. }
  8391. if (symbolType == SL_CLASSPROP)
  8392. {
  8393. if (scope != "")
  8394. {
  8395. // Cannot access non-static members like this
  8396. asCString msg;
  8397. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8398. Error(msg, errNode);
  8399. return -1;
  8400. }
  8401. asCDataType dt;
  8402. if (objType)
  8403. dt = asCDataType::CreateType(objType, false);
  8404. else
  8405. dt = asCDataType::CreateType(outFunc->objectType, false);
  8406. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8407. asASSERT(prop);
  8408. // Is the property access allowed?
  8409. if (prop->isPrivate && prop->isInherited)
  8410. {
  8411. if (engine->ep.privatePropAsProtected)
  8412. {
  8413. // The application is allowing inherited classes to access private properties of the parent
  8414. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  8415. // as it was how the compiler behaved earlier.
  8416. asCString msg;
  8417. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  8418. Warning(msg, errNode);
  8419. }
  8420. else
  8421. {
  8422. asCString msg;
  8423. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8424. Error(msg, errNode);
  8425. }
  8426. }
  8427. if (!objType)
  8428. {
  8429. // The object pointer is located at stack position 0
  8430. // This is only done when accessing through the implicit this pointer
  8431. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8432. ctx->type.SetVariable(dt, 0, false);
  8433. ctx->type.dataType.MakeReference(true);
  8434. Dereference(ctx, true);
  8435. }
  8436. // TODO: This is the same as what is in CompileExpressionPostOp
  8437. // Put the offset on the stack
  8438. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  8439. if (prop->type.IsReference())
  8440. ctx->bc.Instr(asBC_RDSPtr);
  8441. // Reference to primitive must be stored in the temp register
  8442. if (prop->type.IsPrimitive())
  8443. {
  8444. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  8445. ctx->bc.Instr(asBC_PopRPtr);
  8446. }
  8447. // Set the new type (keeping info about temp variable)
  8448. ctx->type.dataType = prop->type;
  8449. ctx->type.dataType.MakeReference(true);
  8450. ctx->type.isVariable = false;
  8451. ctx->type.isLValue = true;
  8452. if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())
  8453. {
  8454. // Objects that are members are not references
  8455. ctx->type.dataType.MakeReference(false);
  8456. // Objects that are members but not handles are safe as long as the parent object is safe
  8457. if (!objType || ctx->type.isRefSafe)
  8458. ctx->type.isRefSafe = true;
  8459. }
  8460. else if (ctx->type.dataType.IsObjectHandle())
  8461. {
  8462. // Objects accessed through handles cannot be considered safe
  8463. // as the handle can be cleared at any time
  8464. ctx->type.isRefSafe = false;
  8465. }
  8466. // If the object reference is const, the property will also be const
  8467. ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
  8468. return 0;
  8469. }
  8470. if (symbolType == SL_CLASSMETHOD)
  8471. {
  8472. if (scope != "")
  8473. {
  8474. // Cannot access non-static members like this
  8475. asCString msg;
  8476. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8477. Error(msg, errNode);
  8478. return -1;
  8479. }
  8480. #if AS_DEBUG
  8481. // If it is not a property, it may still be the name of a method which can be used to create delegates
  8482. asCObjectType *ot = outFunc->objectType;
  8483. asCScriptFunction *func = 0;
  8484. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8485. {
  8486. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8487. if (f->name == name &&
  8488. (builder->module->m_accessMask & f->accessMask))
  8489. {
  8490. func = f;
  8491. break;
  8492. }
  8493. }
  8494. asASSERT(func);
  8495. #endif
  8496. // An object method was found. Keep the name of the method in the expression, but
  8497. // don't actually modify the bytecode at this point since it is not yet known what
  8498. // the method will be used for, or even what overloaded method should be used.
  8499. ctx->methodName = name;
  8500. // Place the object pointer on the stack, as if the expression was this.func
  8501. if (!objType)
  8502. {
  8503. // The object pointer is located at stack position 0
  8504. // This is only done when accessing through the implicit this pointer
  8505. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8506. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  8507. ctx->type.dataType.MakeReference(true);
  8508. Dereference(ctx, true);
  8509. }
  8510. return 0;
  8511. }
  8512. }
  8513. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL)
  8514. {
  8515. // Get the namespace from SymbolLookup
  8516. asSNameSpace *ns = lookupResult.symbolNamespace;
  8517. if (symbolType == SL_GLOBALPROPACCESS)
  8518. {
  8519. // See if there are any matching global property accessors
  8520. asCExprContext access(engine);
  8521. int r = 0;
  8522. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8523. {
  8524. // This is an index access, check if there is a property accessor that takes an index arg
  8525. asCExprContext dummyArg(engine);
  8526. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  8527. }
  8528. if (r == 0)
  8529. {
  8530. // Normal property access
  8531. r = FindPropertyAccessor(name, &access, errNode, ns);
  8532. }
  8533. if (r < 0) return -1;
  8534. if (access.property_get == 0 && access.property_set == 0)
  8535. {
  8536. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8537. asCString msg;
  8538. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8539. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8540. else
  8541. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8542. Error(msg, errNode);
  8543. return -1;
  8544. }
  8545. // Prepare the bytecode for the function call
  8546. MergeExprBytecodeAndType(ctx, &access);
  8547. return 0;
  8548. }
  8549. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR)
  8550. {
  8551. bool isCompiled = true;
  8552. bool isPureConstant = false;
  8553. bool isAppProp = false;
  8554. asQWORD constantValue = 0;
  8555. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8556. asASSERT(prop);
  8557. // Verify that the global property has been compiled already
  8558. if (!isCompiled)
  8559. {
  8560. asCString str;
  8561. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  8562. Error(str, errNode);
  8563. return -1;
  8564. }
  8565. // If the global property is a pure constant
  8566. // we can allow the compiler to optimize it. Pure
  8567. // constants are global constant variables that were
  8568. // initialized by literal constants.
  8569. if (isPureConstant)
  8570. ctx->type.SetConstantData(prop->type, constantValue);
  8571. else
  8572. {
  8573. // A shared type must not access global vars, unless they
  8574. // too are shared, e.g. application registered vars
  8575. if (outFunc->IsShared())
  8576. {
  8577. if (!isAppProp)
  8578. {
  8579. asCString str;
  8580. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  8581. Error(str, errNode);
  8582. // Allow the compilation to continue to catch other problems
  8583. }
  8584. }
  8585. ctx->type.Set(prop->type);
  8586. ctx->type.isLValue = true;
  8587. if (ctx->type.dataType.IsPrimitive())
  8588. {
  8589. // Load the address of the variable into the register
  8590. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  8591. ctx->type.dataType.MakeReference(true);
  8592. }
  8593. else
  8594. {
  8595. // Push the address of the variable on the stack
  8596. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  8597. // If the object is a value type or a non-handle variable to a reference type,
  8598. // then we must validate the existance as it could potentially be accessed
  8599. // before it is initialized.
  8600. // This check is not needed for application registered properties, since they
  8601. // are guaranteed to be valid by the application itself.
  8602. if (!isAppProp &&
  8603. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8604. !ctx->type.dataType.IsObjectHandle()))
  8605. {
  8606. ctx->bc.Instr(asBC_ChkRefS);
  8607. }
  8608. // If the address pushed on the stack is to a value type or an object
  8609. // handle, then mark the expression as a reference. Addresses to a reference
  8610. // type aren't marked as references to get correct behaviour
  8611. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8612. ctx->type.dataType.IsObjectHandle())
  8613. {
  8614. ctx->type.dataType.MakeReference(true);
  8615. }
  8616. else
  8617. {
  8618. asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle());
  8619. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  8620. ctx->bc.Instr(asBC_RDSPtr);
  8621. }
  8622. }
  8623. }
  8624. return 0;
  8625. }
  8626. if (symbolType == SL_GLOBALFUNC)
  8627. {
  8628. asCArray<int> funcs;
  8629. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8630. asASSERT(funcs.GetLength() > 0);
  8631. if (funcs.GetLength() > 0)
  8632. {
  8633. // Defer the evaluation of which function until it is actually used
  8634. // Store the namespace and name of the function for later
  8635. ctx->type.SetUndefinedFuncHandle(engine);
  8636. ctx->methodName = ns ? ns->name + "::" + name : name;
  8637. }
  8638. return 0;
  8639. }
  8640. if (symbolType == SL_ENUMVAL)
  8641. {
  8642. // The enum type and namespace must be returned from SymbolLookup
  8643. asCDataType dt = lookupResult.type.dataType;
  8644. if (!dt.IsEnumType())
  8645. {
  8646. asASSERT(!engine->ep.requireEnumScope);
  8647. // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known
  8648. ctx->enumValue = name.AddressOf();
  8649. ctx->symbolNamespace = lookupResult.symbolNamespace;
  8650. // We cannot set a dummy value because it will pass through
  8651. // cleanly as an integer.
  8652. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8653. return 0;
  8654. }
  8655. asDWORD value = 0;
  8656. builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
  8657. // Even if the enum type is not shared, and we're compiling a shared object,
  8658. // the use of the values are still allowed, since they are treated as constants.
  8659. // an enum value was resolved
  8660. ctx->type.SetConstantDW(dt, value);
  8661. return 0;
  8662. }
  8663. }
  8664. // The result must have been identified above
  8665. if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE)
  8666. {
  8667. // Give dummy value
  8668. ctx->type.SetDummy();
  8669. // The symbol matches a type
  8670. asCString msg;
  8671. asCString smbl;
  8672. if (scope == "::")
  8673. smbl = scope;
  8674. else if (scope != "")
  8675. smbl = scope + "::";
  8676. smbl += name;
  8677. msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf());
  8678. Error(msg, errNode);
  8679. return -1;
  8680. }
  8681. // Should not come here
  8682. asASSERT(false);
  8683. return 0;
  8684. }
  8685. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  8686. {
  8687. // Shouldn't receive any byte code
  8688. asASSERT(ctx->bc.GetLastInstr() == -1);
  8689. asCScriptNode *vnode = node->firstChild;
  8690. ctx->exprNode = vnode;
  8691. if( vnode->nodeType == snVariableAccess )
  8692. {
  8693. // Determine the scope resolution of the variable
  8694. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  8695. // Determine the name of the variable
  8696. asASSERT(vnode->nodeType == snIdentifier );
  8697. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  8698. return CompileVariableAccess(name, scope, ctx, node);
  8699. }
  8700. else if( vnode->nodeType == snConstant )
  8701. {
  8702. if( vnode->tokenType == ttIntConstant )
  8703. {
  8704. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8705. bool overflow = false;
  8706. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  8707. // Is the number bigger than a 64bit word?
  8708. if (overflow)
  8709. {
  8710. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8711. // Set the value to zero to avoid further warnings
  8712. val = 0;
  8713. }
  8714. // Do we need 64 bits?
  8715. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  8716. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  8717. if( val>>31 )
  8718. {
  8719. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  8720. if( val>>63 )
  8721. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8722. else
  8723. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  8724. }
  8725. else
  8726. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  8727. }
  8728. else if( vnode->tokenType == ttBitsConstant )
  8729. {
  8730. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8731. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  8732. bool overflow = false;
  8733. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  8734. // Is the number bigger than a 64bit word?
  8735. if (overflow)
  8736. {
  8737. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8738. // Set the value to zero to avoid further warnings
  8739. val = 0;
  8740. }
  8741. // Do we need 64 bits?
  8742. if( val>>32 )
  8743. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8744. else
  8745. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  8746. }
  8747. else if( vnode->tokenType == ttFloatConstant )
  8748. {
  8749. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8750. // TODO: Check for overflow
  8751. size_t numScanned;
  8752. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  8753. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  8754. #ifndef AS_USE_DOUBLE_AS_FLOAT
  8755. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  8756. asASSERT(numScanned == vnode->tokenLength - 1);
  8757. #endif
  8758. }
  8759. else if( vnode->tokenType == ttDoubleConstant )
  8760. {
  8761. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8762. // TODO: Check for overflow
  8763. size_t numScanned;
  8764. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  8765. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  8766. asASSERT(numScanned == vnode->tokenLength);
  8767. }
  8768. else if( vnode->tokenType == ttTrue ||
  8769. vnode->tokenType == ttFalse )
  8770. {
  8771. #if AS_SIZEOF_BOOL == 1
  8772. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8773. #else
  8774. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8775. #endif
  8776. }
  8777. else if( vnode->tokenType == ttStringConstant ||
  8778. vnode->tokenType == ttMultilineStringConstant ||
  8779. vnode->tokenType == ttHeredocStringConstant )
  8780. {
  8781. asCString str;
  8782. asCScriptNode *snode = vnode->firstChild;
  8783. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  8784. {
  8785. // Treat the single quoted string as a single character literal
  8786. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8787. asDWORD val = 0;
  8788. if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
  8789. {
  8790. // This is the start of a UTF8 encoded character. We need to decode it
  8791. val = asStringDecodeUTF8(str.AddressOf(), 0);
  8792. if( val == (asDWORD)-1 )
  8793. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8794. }
  8795. else
  8796. {
  8797. val = ProcessStringConstant(str, snode);
  8798. if( val == (asDWORD)-1 )
  8799. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8800. }
  8801. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  8802. }
  8803. else
  8804. {
  8805. // Process the string constants
  8806. while( snode )
  8807. {
  8808. asCString cat;
  8809. if( snode->tokenType == ttStringConstant )
  8810. {
  8811. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8812. ProcessStringConstant(cat, snode);
  8813. }
  8814. else if( snode->tokenType == ttMultilineStringConstant )
  8815. {
  8816. if( !engine->ep.allowMultilineStrings )
  8817. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  8818. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8819. ProcessStringConstant(cat, snode);
  8820. }
  8821. else if( snode->tokenType == ttHeredocStringConstant )
  8822. {
  8823. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  8824. ProcessHeredocStringConstant(cat, snode);
  8825. }
  8826. str += cat;
  8827. snode = snode->next;
  8828. }
  8829. // Call the string factory function to create a string object
  8830. if(engine->stringFactory == 0 )
  8831. {
  8832. // Error
  8833. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  8834. // Give dummy value
  8835. ctx->type.SetDummy();
  8836. return -1;
  8837. }
  8838. else
  8839. {
  8840. void *strPtr = const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
  8841. if (strPtr == 0)
  8842. {
  8843. // TODO: A better message is needed
  8844. Error(TXT_NULL_POINTER_ACCESS, vnode);
  8845. ctx->type.SetDummy();
  8846. return -1;
  8847. }
  8848. // Keep the pointer in the list for clean up at exit
  8849. usedStringConstants.PushLast(strPtr);
  8850. // Push the pointer on the stack. The string factory already guarantees that the
  8851. // string object is valid throughout the lifetime of the script so no need to add
  8852. // reference count or make local copy.
  8853. ctx->bc.InstrPTR(asBC_PGA, strPtr);
  8854. ctx->type.Set(engine->stringType);
  8855. // Mark the string as literal constant so the compiler knows it is allowed
  8856. // to treat it differently than an ordinary constant string variable
  8857. ctx->type.isConstant = true;
  8858. // Mark the reference to the string constant as safe, so the compiler can
  8859. // avoid making unnecessary temporary copies when passing the reference to
  8860. // functions.
  8861. ctx->type.isRefSafe = true;
  8862. }
  8863. }
  8864. }
  8865. else if( vnode->tokenType == ttNull )
  8866. {
  8867. ctx->bc.Instr(asBC_PshNull);
  8868. ctx->type.SetNullConstant();
  8869. }
  8870. else
  8871. asASSERT(false);
  8872. }
  8873. else if( vnode->nodeType == snFunctionCall )
  8874. {
  8875. // Determine the scope resolution
  8876. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  8877. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  8878. }
  8879. else if( vnode->nodeType == snConstructCall )
  8880. {
  8881. return CompileConstructCall(vnode, ctx);
  8882. }
  8883. else if( vnode->nodeType == snAssignment )
  8884. {
  8885. asCExprContext e(engine);
  8886. int r = CompileAssignment(vnode, &e);
  8887. if( r < 0 )
  8888. {
  8889. ctx->type.SetDummy();
  8890. return r;
  8891. }
  8892. MergeExprBytecodeAndType(ctx, &e);
  8893. }
  8894. else if( vnode->nodeType == snCast )
  8895. {
  8896. // Implement the cast operator
  8897. return CompileConversion(vnode, ctx);
  8898. }
  8899. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  8900. {
  8901. // This is a void expression
  8902. ctx->SetVoidExpression();
  8903. }
  8904. else if( vnode->nodeType == snFunction )
  8905. {
  8906. // This is an anonymous function
  8907. // Defer the evaluation of the function until it is known where it
  8908. // will be used, which is where the signature will be defined
  8909. ctx->SetLambda(vnode);
  8910. }
  8911. else
  8912. asASSERT(false);
  8913. return 0;
  8914. }
  8915. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  8916. {
  8917. int charLiteral = -1;
  8918. // Process escape sequences
  8919. asCArray<char> str((int)cstr.GetLength());
  8920. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  8921. {
  8922. #ifdef AS_DOUBLEBYTE_CHARSET
  8923. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  8924. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  8925. {
  8926. // This is the lead character of a double byte character
  8927. // include the trail character without checking it's value.
  8928. str.PushLast(cstr[n]);
  8929. n++;
  8930. str.PushLast(cstr[n]);
  8931. continue;
  8932. }
  8933. #endif
  8934. asUINT val;
  8935. if( processEscapeSequences && cstr[n] == '\\' )
  8936. {
  8937. ++n;
  8938. if( n == cstr.GetLength() )
  8939. {
  8940. if( charLiteral == -1 ) charLiteral = 0;
  8941. return charLiteral;
  8942. }
  8943. // Hexadecimal escape sequences will allow the construction of
  8944. // invalid unicode sequences, but the string should also work as
  8945. // a bytearray so we must support this. The code for working with
  8946. // unicode text must be prepared to handle invalid unicode sequences
  8947. if( cstr[n] == 'x' || cstr[n] == 'X' )
  8948. {
  8949. ++n;
  8950. if( n == cstr.GetLength() ) break;
  8951. val = 0;
  8952. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  8953. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  8954. {
  8955. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8956. val = val*16 + cstr[n] - '0';
  8957. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8958. val = val*16 + cstr[n] - 'a' + 10;
  8959. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8960. val = val*16 + cstr[n] - 'A' + 10;
  8961. else
  8962. break;
  8963. }
  8964. // Rewind one, since the loop will increment it again
  8965. n--;
  8966. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  8967. if( engine->ep.stringEncoding == 0 )
  8968. {
  8969. str.PushLast((asBYTE)val);
  8970. }
  8971. else
  8972. {
  8973. #ifndef AS_BIG_ENDIAN
  8974. str.PushLast((asBYTE)val);
  8975. str.PushLast((asBYTE)(val>>8));
  8976. #else
  8977. str.PushLast((asBYTE)(val>>8));
  8978. str.PushLast((asBYTE)val);
  8979. #endif
  8980. }
  8981. if( charLiteral == -1 ) charLiteral = val;
  8982. continue;
  8983. }
  8984. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  8985. {
  8986. // \u expects 4 hex digits
  8987. // \U expects 8 hex digits
  8988. bool expect2 = cstr[n] == 'u';
  8989. int c = expect2 ? 4 : 8;
  8990. val = 0;
  8991. for( ; c > 0; c-- )
  8992. {
  8993. ++n;
  8994. if( n == cstr.GetLength() ) break;
  8995. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8996. val = val*16 + cstr[n] - '0';
  8997. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8998. val = val*16 + cstr[n] - 'a' + 10;
  8999. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  9000. val = val*16 + cstr[n] - 'A' + 10;
  9001. else
  9002. break;
  9003. }
  9004. if( c != 0 )
  9005. {
  9006. // Give warning about invalid code point
  9007. // TODO: Need code position for warning
  9008. asCString msg;
  9009. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  9010. Warning(msg, node);
  9011. continue;
  9012. }
  9013. }
  9014. else
  9015. {
  9016. if( cstr[n] == '"' )
  9017. val = '"';
  9018. else if( cstr[n] == '\'' )
  9019. val = '\'';
  9020. else if( cstr[n] == 'n' )
  9021. val = '\n';
  9022. else if( cstr[n] == 'r' )
  9023. val = '\r';
  9024. else if( cstr[n] == 't' )
  9025. val = '\t';
  9026. else if( cstr[n] == '0' )
  9027. val = '\0';
  9028. else if( cstr[n] == '\\' )
  9029. val = '\\';
  9030. else
  9031. {
  9032. // Invalid escape sequence
  9033. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  9034. continue;
  9035. }
  9036. }
  9037. }
  9038. else
  9039. {
  9040. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  9041. {
  9042. unsigned int len;
  9043. val = asStringDecodeUTF8(&cstr[n], &len);
  9044. if( val == 0xFFFFFFFF )
  9045. {
  9046. // Incorrect UTF8 encoding. Use only the first byte
  9047. // TODO: Need code position for warning
  9048. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  9049. val = (unsigned char)cstr[n];
  9050. }
  9051. else
  9052. n += len-1;
  9053. }
  9054. else
  9055. val = (unsigned char)cstr[n];
  9056. }
  9057. // Add the character to the final string
  9058. char encodedValue[5];
  9059. int len;
  9060. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  9061. {
  9062. // Convert to UTF8 encoded
  9063. len = asStringEncodeUTF8(val, encodedValue);
  9064. }
  9065. else if( engine->ep.stringEncoding == 1 )
  9066. {
  9067. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  9068. len = asStringEncodeUTF16(val, encodedValue);
  9069. }
  9070. else
  9071. {
  9072. // Do not convert ASCII characters
  9073. encodedValue[0] = (asBYTE)val;
  9074. len = 1;
  9075. }
  9076. if( len < 0 )
  9077. {
  9078. // Give warning about invalid code point
  9079. // TODO: Need code position for warning
  9080. Warning(TXT_INVALID_UNICODE_VALUE, node);
  9081. }
  9082. else
  9083. {
  9084. // Add the encoded value to the final string
  9085. str.Concatenate(encodedValue, len);
  9086. if( charLiteral == -1 ) charLiteral = val;
  9087. }
  9088. }
  9089. cstr.Assign(str.AddressOf(), str.GetLength());
  9090. return charLiteral;
  9091. }
  9092. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  9093. {
  9094. // Remove first line if it only contains whitespace
  9095. bool isMultiline = false;
  9096. int start;
  9097. for( start = 0; start < (int)str.GetLength(); start++ )
  9098. {
  9099. if( str[start] == '\n' )
  9100. {
  9101. isMultiline = true;
  9102. // Remove the linebreak as well
  9103. start++;
  9104. break;
  9105. }
  9106. if( str[start] != ' ' &&
  9107. str[start] != '\t' &&
  9108. str[start] != '\r' )
  9109. {
  9110. // Don't remove anything
  9111. start = 0;
  9112. break;
  9113. }
  9114. }
  9115. // Remove the line after the last line break if it only contains whitespaces
  9116. int end;
  9117. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  9118. {
  9119. if( str[end] == '\n' )
  9120. {
  9121. // Don't remove the last line break
  9122. end++;
  9123. break;
  9124. }
  9125. if( str[end] != ' ' &&
  9126. str[end] != '\t' &&
  9127. str[end] != '\r' )
  9128. {
  9129. // Don't remove anything
  9130. end = (int)str.GetLength();
  9131. break;
  9132. }
  9133. }
  9134. if( end < 0 ) end = 0;
  9135. asCString tmp;
  9136. if (end > start || engine->ep.heredocTrimMode != 2 )
  9137. {
  9138. // if heredocTrimMode == 0 the string shouldn't be trimmed
  9139. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  9140. // if heredocTrimMode == 2 the string should always be trimmed
  9141. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  9142. tmp.Assign(&str[start], end - start);
  9143. else
  9144. tmp = str;
  9145. }
  9146. ProcessStringConstant(tmp, node, false);
  9147. str = tmp;
  9148. }
  9149. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  9150. {
  9151. asCExprContext expr(engine);
  9152. asCDataType to;
  9153. bool anyErrors = false;
  9154. EImplicitConv convType;
  9155. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  9156. {
  9157. convType = asIC_EXPLICIT_VAL_CAST;
  9158. // Verify that there is only one argument
  9159. if( node->lastChild->firstChild == 0 ||
  9160. node->lastChild->firstChild != node->lastChild->lastChild )
  9161. {
  9162. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  9163. expr.type.SetDummy();
  9164. anyErrors = true;
  9165. }
  9166. else if (node->lastChild->firstChild &&
  9167. node->lastChild->firstChild->nodeType == snNamedArgument)
  9168. {
  9169. Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
  9170. expr.type.SetDummy();
  9171. anyErrors = true;
  9172. }
  9173. else
  9174. {
  9175. // Compile the expression
  9176. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  9177. if( r < 0 )
  9178. anyErrors = true;
  9179. }
  9180. // Determine the requested type
  9181. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9182. to.MakeReadOnly(true); // Default to const
  9183. asASSERT(to.IsPrimitive());
  9184. }
  9185. else
  9186. {
  9187. convType = asIC_EXPLICIT_REF_CAST;
  9188. // Compile the expression
  9189. int r = CompileAssignment(node->lastChild, &expr);
  9190. if( r < 0 )
  9191. anyErrors = true;
  9192. // Determine the requested type
  9193. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9194. // If the type support object handles, then use it
  9195. if( to.SupportHandles() )
  9196. {
  9197. to.MakeHandle(true);
  9198. if( expr.type.dataType.IsObjectConst() )
  9199. to.MakeHandleToConst(true);
  9200. }
  9201. else if( !to.IsObjectHandle() )
  9202. {
  9203. // The cast<type> operator can only be used for reference casts
  9204. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  9205. anyErrors = true;
  9206. }
  9207. }
  9208. // Do not allow casting to non shared type if we're compiling a shared method
  9209. if( outFunc->IsShared() &&
  9210. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  9211. {
  9212. asCString msg;
  9213. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  9214. Error(msg, node);
  9215. anyErrors = true;
  9216. }
  9217. if( anyErrors )
  9218. {
  9219. // Assume that the error can be fixed and allow the compilation to continue
  9220. ctx->type.Set(to);
  9221. return -1;
  9222. }
  9223. if( ProcessPropertyGetAccessor(&expr, node) < 0 )
  9224. return -1;
  9225. // Don't allow any operators on expressions that take address of class method
  9226. if( expr.IsClassMethod() )
  9227. {
  9228. Error(TXT_INVALID_OP_ON_METHOD, node);
  9229. return -1;
  9230. }
  9231. // We don't want a reference for conversion casts
  9232. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  9233. {
  9234. if( expr.type.dataType.IsObject() )
  9235. Dereference(&expr, true);
  9236. else
  9237. ConvertToVariable(&expr);
  9238. }
  9239. ImplicitConversion(&expr, to, node, convType);
  9240. IsVariableInitialized(&expr.type, node);
  9241. // If no type conversion is really tried ignore it
  9242. if( to == expr.type.dataType )
  9243. {
  9244. // This will keep information about constant type
  9245. MergeExprBytecode(ctx, &expr);
  9246. ctx->type = expr.type;
  9247. return 0;
  9248. }
  9249. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  9250. {
  9251. MergeExprBytecode(ctx, &expr);
  9252. ctx->type = expr.type;
  9253. ctx->type.dataType.MakeReadOnly(true);
  9254. return 0;
  9255. }
  9256. // The implicit conversion already does most of the conversions permitted,
  9257. // here we'll only treat those conversions that require an explicit cast.
  9258. bool conversionOK = false;
  9259. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  9260. {
  9261. if( !expr.type.dataType.IsObject() )
  9262. ConvertToTempVariable(&expr);
  9263. if( to.IsObjectHandle() &&
  9264. expr.type.dataType.IsObjectHandle() &&
  9265. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  9266. {
  9267. conversionOK = CompileRefCast(&expr, to, true, node);
  9268. MergeExprBytecode(ctx, &expr);
  9269. ctx->type = expr.type;
  9270. }
  9271. }
  9272. if( conversionOK )
  9273. return 0;
  9274. // Conversion not available
  9275. ctx->type.SetDummy();
  9276. asCString strTo, strFrom;
  9277. strTo = to.Format(outFunc->nameSpace);
  9278. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  9279. asCString msg;
  9280. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  9281. Error(msg, node);
  9282. return -1;
  9283. }
  9284. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  9285. {
  9286. // deferAll is set to true if for example the function returns a reference, since in
  9287. // this case the function might be returning a reference to one of the arguments.
  9288. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  9289. // Parameters that are sent by reference should be assigned
  9290. // to the evaluated expression if it is an lvalue
  9291. // Evaluate the arguments from last to first
  9292. int n = (int)descr->parameterTypes.GetLength() - 1;
  9293. for( ; n >= 0; n-- )
  9294. {
  9295. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  9296. // If deferAll is set all objects passed by reference or handle must be deferred
  9297. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  9298. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  9299. {
  9300. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  9301. // For &inout, only store the argument if it is for a temporary variable
  9302. if( engine->ep.allowUnsafeReferences ||
  9303. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  9304. {
  9305. // Store the argument for later processing
  9306. asSDeferredParam outParam;
  9307. outParam.argNode = args[n]->exprNode;
  9308. outParam.argType = args[n]->type;
  9309. outParam.argInOutFlags = descr->inOutFlags[n];
  9310. outParam.origExpr = args[n]->origExpr;
  9311. ctx->deferredParams.PushLast(outParam);
  9312. }
  9313. }
  9314. else
  9315. {
  9316. // Release the temporary variable now
  9317. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  9318. }
  9319. // Move the argument's deferred expressions over to the final expression
  9320. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  9321. {
  9322. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  9323. args[n]->deferredParams[m].origExpr = 0;
  9324. }
  9325. args[n]->deferredParams.SetLength(0);
  9326. }
  9327. }
  9328. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  9329. {
  9330. if( isProcessingDeferredParams ) return;
  9331. isProcessingDeferredParams = true;
  9332. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  9333. {
  9334. asSDeferredParam outParam = ctx->deferredParams[n];
  9335. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  9336. {
  9337. // Just release the variable
  9338. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9339. }
  9340. else if( outParam.argInOutFlags == asTM_OUTREF )
  9341. {
  9342. asCExprContext *expr = outParam.origExpr;
  9343. outParam.origExpr = 0;
  9344. if( outParam.argType.dataType.IsObjectHandle() )
  9345. {
  9346. // Implicitly convert the value to a handle
  9347. if( expr->type.dataType.IsObjectHandle() )
  9348. expr->type.isExplicitHandle = true;
  9349. }
  9350. // Verify that the expression result in a lvalue, or a property accessor
  9351. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  9352. {
  9353. asCExprContext rctx(engine);
  9354. rctx.type = outParam.argType;
  9355. if( rctx.type.dataType.IsPrimitive() )
  9356. rctx.type.dataType.MakeReference(false);
  9357. else
  9358. {
  9359. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  9360. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  9361. if( expr->type.isExplicitHandle )
  9362. rctx.type.isExplicitHandle = true;
  9363. }
  9364. asCExprContext o(engine);
  9365. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  9366. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  9367. // The assignment may itself have resulted in a new temporary variable, e.g. if
  9368. // the opAssign returns a non-reference. We must release this temporary variable
  9369. // since it won't be used
  9370. ReleaseTemporaryVariable(o.type, &o.bc);
  9371. MergeExprBytecode(ctx, &o);
  9372. }
  9373. else
  9374. {
  9375. // We must still evaluate the expression
  9376. MergeExprBytecode(ctx, expr);
  9377. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  9378. ctx->bc.Instr(asBC_PopPtr);
  9379. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  9380. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() &&
  9381. !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) )
  9382. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  9383. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9384. }
  9385. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  9386. // Delete the original expression context
  9387. asDELETE(expr, asCExprContext);
  9388. }
  9389. else // &inout
  9390. {
  9391. if( outParam.argType.isTemporary )
  9392. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9393. else if( !outParam.argType.isVariable )
  9394. {
  9395. if( outParam.argType.dataType.IsObject() &&
  9396. ((outParam.argType.dataType.GetBehaviour()->addref &&
  9397. outParam.argType.dataType.GetBehaviour()->release) ||
  9398. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  9399. {
  9400. // Release the object handle that was taken to guarantee the reference
  9401. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9402. }
  9403. }
  9404. }
  9405. }
  9406. ctx->deferredParams.SetLength(0);
  9407. isProcessingDeferredParams = false;
  9408. }
  9409. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  9410. {
  9411. // The first node is a datatype node
  9412. asCString name;
  9413. asCExprValue tempObj;
  9414. bool onHeap = true;
  9415. asCArray<int> funcs;
  9416. bool error = false;
  9417. // It is possible that the name is really a constructor
  9418. asCDataType dt;
  9419. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  9420. if( dt.IsPrimitive() )
  9421. {
  9422. // This is a cast to a primitive type
  9423. return CompileConversion(node, ctx);
  9424. }
  9425. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  9426. {
  9427. // Types declared as implicit handle must not attempt to construct a handle
  9428. dt.MakeHandle(false);
  9429. }
  9430. // Don't accept syntax like object@(expr)
  9431. if( dt.IsObjectHandle() )
  9432. {
  9433. asCString str;
  9434. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  9435. Error(str, node);
  9436. ctx->type.SetDummy();
  9437. return -1;
  9438. }
  9439. // Make sure the desired type can actually be instantiated
  9440. // Delegates are allowed to be created through construct calls,
  9441. // even though they cannot be instantiated as variables
  9442. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  9443. {
  9444. asCString str;
  9445. if( dt.IsAbstractClass() )
  9446. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9447. else if( dt.IsInterface() )
  9448. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9449. else
  9450. // TODO: Improve error message to explain why
  9451. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  9452. Error(str, node);
  9453. ctx->type.SetDummy();
  9454. return -1;
  9455. }
  9456. // Do not allow constructing non-shared types in shared functions
  9457. if( outFunc->IsShared() &&
  9458. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  9459. {
  9460. asCString msg;
  9461. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  9462. Error(msg, node);
  9463. return -1;
  9464. }
  9465. // Compile the arguments
  9466. asCArray<asCExprContext *> args;
  9467. asCArray<asSNamedArgument> namedArgs;
  9468. asCArray<asCExprValue> temporaryVariables;
  9469. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9470. {
  9471. // Check for a value cast behaviour
  9472. if( args.GetLength() == 1 )
  9473. {
  9474. asCExprContext conv(engine);
  9475. conv.Copy(args[0]);
  9476. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  9477. // Clean the property_arg in the temporary copy so
  9478. // it isn't deleted when conv goes out of scope
  9479. conv.property_arg = 0;
  9480. // Don't use this if the cost is 0 because it would mean that nothing
  9481. // is done and the script wants a new value to be constructed
  9482. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  9483. {
  9484. // Make sure the result is a reference, just as if to a local variable
  9485. if( !dt.IsFuncdef() )
  9486. dt.MakeReference(true);
  9487. // Make sure any property accessor is already evaluated
  9488. if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 )
  9489. return -1;
  9490. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  9491. ctx->bc.AddCode(&args[0]->bc);
  9492. ctx->type = args[0]->type;
  9493. asDELETE(args[0], asCExprContext);
  9494. return 0;
  9495. }
  9496. }
  9497. // Check for possible constructor/factory
  9498. name = dt.Format(outFunc->nameSpace);
  9499. asSTypeBehaviour *beh = dt.GetBehaviour();
  9500. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  9501. {
  9502. funcs = beh->constructors;
  9503. // Value types and script types are allocated through the constructor
  9504. tempObj.dataType = dt;
  9505. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  9506. tempObj.dataType.MakeReference(true);
  9507. tempObj.isTemporary = true;
  9508. tempObj.isVariable = true;
  9509. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  9510. // Push the address of the object on the stack
  9511. if( onHeap )
  9512. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  9513. }
  9514. else if( beh )
  9515. funcs = beh->factories;
  9516. // Special case: Allow calling func(void) with a void expression.
  9517. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  9518. {
  9519. // Evaluate the expression before the function call
  9520. MergeExprBytecode(ctx, args[0]);
  9521. asDELETE(args[0], asCExprContext);
  9522. args.SetLength(0);
  9523. }
  9524. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  9525. // If none has been registered, just allocate the variable and push it on the stack.
  9526. if( args.GetLength() == 0 )
  9527. {
  9528. beh = tempObj.dataType.GetBehaviour();
  9529. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9530. {
  9531. // Call the default constructor
  9532. ctx->type = tempObj;
  9533. if( onHeap )
  9534. {
  9535. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  9536. ctx->bc.RemoveLastInstr();
  9537. }
  9538. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  9539. // Push the reference on the stack
  9540. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9541. return 0;
  9542. }
  9543. }
  9544. // Special case: If this is a construction of a delegate and the expression names an object method
  9545. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  9546. {
  9547. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  9548. // case no object delegate will be created, but instead a delegate for a function pointer
  9549. // In theory a simple cast would be good in this case, but this is a construct call so it
  9550. // is expected that a new object is created.
  9551. dt.MakeHandle(true);
  9552. ctx->type.Set(dt);
  9553. // The delegate must be able to hold on to a reference to the object
  9554. if( !args[0]->type.dataType.SupportHandles() )
  9555. {
  9556. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  9557. error = true;
  9558. }
  9559. else
  9560. {
  9561. // Filter the available object methods to find the one that matches the func def
  9562. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  9563. asCScriptFunction *bestMethod = 0;
  9564. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  9565. {
  9566. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  9567. if( func->name != args[0]->methodName )
  9568. continue;
  9569. // If the expression is for a const object, then only const methods should be accepted
  9570. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  9571. continue;
  9572. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  9573. {
  9574. bestMethod = func;
  9575. // If the expression is non-const the non-const overloaded method has priority
  9576. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  9577. break;
  9578. }
  9579. }
  9580. if( bestMethod )
  9581. {
  9582. // The object pointer is already on the stack
  9583. MergeExprBytecode(ctx, args[0]);
  9584. // Push the function pointer as an additional argument
  9585. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  9586. // Call the factory function for the delegate
  9587. asCArray<int> delegateFuncs;
  9588. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  9589. asASSERT(delegateFuncs.GetLength() == 1 );
  9590. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  9591. // Store the returned delegate in a temporary variable
  9592. int returnOffset = AllocateVariable(dt, true, false);
  9593. dt.MakeReference(true);
  9594. ctx->type.SetVariable(dt, returnOffset, true);
  9595. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9596. // Push a reference to the temporary variable on the stack
  9597. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9598. // Clean up arguments
  9599. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  9600. }
  9601. else
  9602. {
  9603. asCString msg;
  9604. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  9605. Error(msg.AddressOf(), node);
  9606. error = true;
  9607. }
  9608. }
  9609. // Clean-up arg
  9610. asDELETE(args[0], asCExprContext);
  9611. return error ? -1 : 0;
  9612. }
  9613. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  9614. if( funcs.GetLength() != 1 )
  9615. {
  9616. // The error was reported by MatchFunctions()
  9617. error = true;
  9618. // Dummy value
  9619. ctx->type.SetDummy();
  9620. }
  9621. else
  9622. {
  9623. // TODO: Clean up: Merge this with MakeFunctionCall
  9624. // Add the default values for arguments not explicitly supplied
  9625. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  9626. if( r == asSUCCESS )
  9627. {
  9628. asCByteCode objBC(engine);
  9629. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  9630. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  9631. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9632. {
  9633. // If the object is allocated on the stack, then call the constructor as a normal function
  9634. if( onHeap )
  9635. {
  9636. int offset = 0;
  9637. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  9638. for( asUINT n = 0; n < args.GetLength(); n++ )
  9639. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  9640. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  9641. }
  9642. else
  9643. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9644. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  9645. // Add tag that the object has been initialized
  9646. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  9647. // The constructor doesn't return anything,
  9648. // so we have to manually inform the type of
  9649. // the return value
  9650. ctx->type = tempObj;
  9651. if( !onHeap )
  9652. ctx->type.dataType.MakeReference(false);
  9653. // Push the address of the object on the stack again
  9654. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9655. }
  9656. else
  9657. {
  9658. // Call the factory to create the reference type
  9659. PerformFunctionCall(funcs[0], ctx, false, &args);
  9660. }
  9661. }
  9662. else
  9663. error = true;
  9664. }
  9665. }
  9666. else
  9667. {
  9668. // Failed to compile the argument list, set the result to the dummy type
  9669. ctx->type.SetDummy();
  9670. error = true;
  9671. }
  9672. // Cleanup
  9673. for( asUINT n = 0; n < args.GetLength(); n++ )
  9674. if( args[n] )
  9675. {
  9676. asDELETE(args[n], asCExprContext);
  9677. }
  9678. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9679. if( namedArgs[n].ctx )
  9680. {
  9681. asDELETE(namedArgs[n].ctx, asCExprContext);
  9682. }
  9683. return error ? -1 : 0;
  9684. }
  9685. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  9686. {
  9687. asCExprValue tempObj;
  9688. asCArray<int> funcs;
  9689. int localVar = -1;
  9690. bool initializeMembers = false;
  9691. asCExprContext funcExpr(engine);
  9692. asCScriptNode *nm = node->lastChild->prev;
  9693. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  9694. // Find the matching entities
  9695. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  9696. asCExprContext lookupResult(engine);
  9697. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult);
  9698. if (symbolType < 0)
  9699. return -1;
  9700. if (symbolType == SL_NOMATCH)
  9701. {
  9702. // No matching symbol
  9703. asCString msg;
  9704. asCString smbl;
  9705. if (scope == "::")
  9706. smbl = scope;
  9707. else if (scope != "")
  9708. smbl = scope + "::";
  9709. smbl += name;
  9710. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  9711. Error(msg, node);
  9712. return -1;
  9713. }
  9714. // Is the symbol matching a variable/property?
  9715. if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ||
  9716. symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP ||
  9717. symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL)
  9718. {
  9719. // Variables/properties can be used as functions if they have the opCall
  9720. // Compile the variable
  9721. // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
  9722. localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
  9723. if( localVar < 0 )
  9724. return -1;
  9725. if (funcExpr.type.dataType.IsFuncdef())
  9726. {
  9727. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  9728. }
  9729. else if (funcExpr.type.dataType.IsObject())
  9730. {
  9731. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  9732. if (ctx->type.isTemporary)
  9733. {
  9734. asASSERT(objectType);
  9735. asSDeferredParam deferred;
  9736. deferred.origExpr = 0;
  9737. deferred.argInOutFlags = asTM_INREF;
  9738. deferred.argNode = 0;
  9739. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9740. ctx->deferredParams.PushLast(deferred);
  9741. }
  9742. if (funcExpr.property_get == 0)
  9743. Dereference(ctx, true);
  9744. // Add the bytecode for accessing the object on which opCall will be called
  9745. if (ctx->type.dataType.IsObject())
  9746. {
  9747. // Make sure the ProcessPropertyGetAccess knows whether or not to
  9748. // dereference the original object before calling the get accessor
  9749. funcExpr.property_ref = ctx->type.dataType.IsReference();
  9750. }
  9751. MergeExprBytecodeAndType(ctx, &funcExpr);
  9752. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  9753. return -1;
  9754. Dereference(ctx, true);
  9755. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  9756. // Get the opCall methods from the object type
  9757. if (funcExpr.type.dataType.IsObjectHandle())
  9758. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  9759. else
  9760. objIsConst = funcExpr.type.dataType.IsReadOnly();
  9761. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  9762. }
  9763. else
  9764. {
  9765. // The variable is not a function or object with opCall
  9766. asCString msg;
  9767. msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf());
  9768. Error(msg, node);
  9769. return -1;
  9770. }
  9771. }
  9772. // Is the symbol matching a class method?
  9773. if (symbolType == SL_CLASSMETHOD)
  9774. {
  9775. // If we're compiling a constructor and the name of the function is super then
  9776. // the constructor of the base class is being called.
  9777. // super cannot be prefixed with a scope operator
  9778. if (scope == "" && m_isConstructor && name == SUPER_TOKEN)
  9779. {
  9780. // If the class is not derived from anyone else, calling super should give an error
  9781. if (outFunc && outFunc->objectType->derivedFrom)
  9782. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  9783. // Must not allow calling base class' constructor multiple times
  9784. if (continueLabels.GetLength() > 0)
  9785. {
  9786. // If a continue label is set we are in a loop
  9787. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  9788. }
  9789. else if (breakLabels.GetLength() > 0)
  9790. {
  9791. // TODO: inheritance: Should eventually allow constructors in switch statements
  9792. // If a break label is set we are either in a loop or a switch statements
  9793. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  9794. }
  9795. else if (m_isConstructorCalled)
  9796. {
  9797. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  9798. }
  9799. m_isConstructorCalled = true;
  9800. // We need to initialize the class members, but only after all the deferred arguments have been completed
  9801. initializeMembers = true;
  9802. }
  9803. else
  9804. {
  9805. // The scope can be used to specify the base class
  9806. builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script);
  9807. }
  9808. // If a class method is being called implicitly, then add the this pointer for the call
  9809. if (funcs.GetLength() && !objectType && outFunc->objectType)
  9810. {
  9811. // Verify that the identified function is actually part of the class hierarchy
  9812. if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
  9813. {
  9814. asCString msg;
  9815. asCString mthd;
  9816. if (scope == "")
  9817. mthd = name;
  9818. else if (scope == "::")
  9819. mthd = scope + name;
  9820. else
  9821. mthd = scope + "::" + name;
  9822. msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf());
  9823. Error(msg, node);
  9824. return -1;
  9825. }
  9826. objectType = outFunc->objectType;
  9827. asCDataType dt = asCDataType::CreateType(objectType, false);
  9828. // The object pointer is located at stack position 0
  9829. ctx->bc.InstrSHORT(asBC_PSF, 0);
  9830. ctx->type.SetVariable(dt, 0, false);
  9831. ctx->type.dataType.MakeReference(true);
  9832. Dereference(ctx, true);
  9833. }
  9834. else if (funcs.GetLength() && !objectType && !outFunc->objectType)
  9835. {
  9836. // Cannot call class methods directly without the object
  9837. asCString msg;
  9838. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  9839. Error(msg, node);
  9840. return -1;
  9841. }
  9842. }
  9843. // Is it a global function?
  9844. if (symbolType == SL_GLOBALFUNC)
  9845. {
  9846. // The symbol lookup identified the namespace to use
  9847. int n = lookupResult.methodName.FindLast("::");
  9848. asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf());
  9849. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  9850. }
  9851. // Is it a type?
  9852. if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE)
  9853. {
  9854. bool isValid = false;
  9855. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid);
  9856. if (isValid)
  9857. return CompileConstructCall(node, ctx);
  9858. }
  9859. // Compile the arguments
  9860. asCArray<asCExprContext *> args;
  9861. asCArray<asSNamedArgument> namedArgs;
  9862. bool isOK = true;
  9863. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9864. {
  9865. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  9866. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  9867. {
  9868. // Evaluate the expression before the function call
  9869. MergeExprBytecode(ctx, args[0]);
  9870. asDELETE(args[0], asCExprContext);
  9871. args.SetLength(0);
  9872. }
  9873. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  9874. if( funcs.GetLength() != 1 )
  9875. {
  9876. // The error was reported by MatchFunctions()
  9877. // Dummy value
  9878. ctx->type.SetDummy();
  9879. isOK = false;
  9880. }
  9881. else
  9882. {
  9883. // Add the default values for arguments not explicitly supplied
  9884. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  9885. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9886. // is it enough to make sure it is in a local variable?
  9887. // For function pointer we must guarantee that the function is safe, i.e.
  9888. // by first storing the function pointer in a local variable (if it isn't already in one)
  9889. if( r == asSUCCESS )
  9890. {
  9891. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  9892. if( func->funcType == asFUNC_FUNCDEF )
  9893. {
  9894. if( objectType && funcExpr.property_get <= 0 )
  9895. {
  9896. // Dereference the object pointer to access the member
  9897. Dereference(ctx, true);
  9898. }
  9899. if( funcExpr.property_get > 0 )
  9900. {
  9901. if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 )
  9902. return -1;
  9903. Dereference(&funcExpr, true);
  9904. }
  9905. else
  9906. {
  9907. Dereference(&funcExpr, true);
  9908. ConvertToVariable(&funcExpr);
  9909. }
  9910. // The actual function should be called as if a global function
  9911. objectType = 0;
  9912. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  9913. funcExpr.bc.Instr(asBC_PopPtr);
  9914. asCExprValue tmp = ctx->type;
  9915. MergeExprBytecodeAndType(ctx, &funcExpr);
  9916. ReleaseTemporaryVariable(tmp, &ctx->bc);
  9917. }
  9918. r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  9919. if( r < 0 )
  9920. {
  9921. ctx->type.SetDummy();
  9922. isOK = false;
  9923. }
  9924. }
  9925. else
  9926. isOK = false;
  9927. }
  9928. }
  9929. else
  9930. {
  9931. // Failed to compile the argument list, set the dummy type and continue compilation
  9932. ctx->type.SetDummy();
  9933. isOK = false;
  9934. }
  9935. // Cleanup
  9936. for( asUINT n = 0; n < args.GetLength(); n++ )
  9937. if( args[n] )
  9938. {
  9939. asDELETE(args[n], asCExprContext);
  9940. }
  9941. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9942. if( namedArgs[n].ctx )
  9943. {
  9944. asDELETE(namedArgs[n].ctx, asCExprContext);
  9945. }
  9946. if( initializeMembers )
  9947. {
  9948. asASSERT( m_isConstructor );
  9949. // Need to initialize members here, as they may use the properties of the base class
  9950. // If there are multiple paths that call super(), then there will also be multiple
  9951. // locations with initializations of the members. It is not possible to consolidate
  9952. // these in one place, as the expressions for the initialization are evaluated where
  9953. // they are compiled, which means that they may access different variables depending
  9954. // on the scope where super() is called.
  9955. // Members that don't have an explicit initialization expression will be initialized
  9956. // beginning of the constructor as they are guaranteed not to use at the any
  9957. // members of the base class.
  9958. CompileMemberInitialization(&ctx->bc, false);
  9959. }
  9960. return isOK ? 0 : -1;
  9961. }
  9962. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  9963. {
  9964. asSNameSpace *ns;
  9965. if( scope == "" )
  9966. {
  9967. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  9968. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  9969. ns = outFunc->nameSpace;
  9970. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  9971. ns = outFunc->objectType->nameSpace;
  9972. else
  9973. ns = engine->nameSpaces[0];
  9974. }
  9975. else if( scope == "::" )
  9976. ns = engine->nameSpaces[0];
  9977. else
  9978. ns = engine->FindNameSpace(scope.AddressOf());
  9979. return ns;
  9980. }
  9981. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  9982. {
  9983. int op = node->tokenType;
  9984. // Don't allow any prefix operators except handle on expressions that take address of class method
  9985. if( ctx->IsClassMethod() && op != ttHandle )
  9986. {
  9987. Error(TXT_INVALID_OP_ON_METHOD, node);
  9988. return -1;
  9989. }
  9990. // Don't allow any operators on void expressions
  9991. if( ctx->IsVoidExpression() )
  9992. {
  9993. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9994. return -1;
  9995. }
  9996. IsVariableInitialized(&ctx->type, node);
  9997. if( op == ttHandle )
  9998. {
  9999. if( ctx->methodName != "" )
  10000. {
  10001. // Don't allow taking the handle of a handle
  10002. if( ctx->type.isExplicitHandle )
  10003. {
  10004. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10005. return -1;
  10006. }
  10007. }
  10008. else
  10009. {
  10010. // Don't allow taking handle of a handle, i.e. @@
  10011. if( ctx->type.isExplicitHandle )
  10012. {
  10013. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10014. return -1;
  10015. }
  10016. // @null is allowed even though it is implicit
  10017. if( !ctx->type.IsNullConstant() )
  10018. {
  10019. // Verify that the type allow its handle to be taken
  10020. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  10021. {
  10022. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10023. return -1;
  10024. }
  10025. // Objects that are not local variables are not references
  10026. // Objects allocated on the stack are also not marked as references
  10027. if( !ctx->type.dataType.IsReference() &&
  10028. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  10029. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  10030. {
  10031. Error(TXT_NOT_VALID_REFERENCE, node);
  10032. return -1;
  10033. }
  10034. // Convert the expression to a handle
  10035. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  10036. {
  10037. asCDataType to = ctx->type.dataType;
  10038. to.MakeHandle(true);
  10039. to.MakeReference(true);
  10040. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  10041. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  10042. asASSERT( ctx->type.dataType.IsObjectHandle() );
  10043. }
  10044. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  10045. {
  10046. // For the ASHANDLE type we'll simply set the expression as a handle
  10047. ctx->type.dataType.MakeHandle(true);
  10048. }
  10049. }
  10050. }
  10051. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  10052. ctx->type.isExplicitHandle = true;
  10053. }
  10054. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10055. {
  10056. // Look for the appropriate method
  10057. // There is no overloadable operator for unary plus
  10058. const char *opName = 0;
  10059. switch( op )
  10060. {
  10061. case ttMinus: opName = "opNeg"; break;
  10062. case ttBitNot: opName = "opCom"; break;
  10063. case ttInc: opName = "opPreInc"; break;
  10064. case ttDec: opName = "opPreDec"; break;
  10065. }
  10066. if( opName )
  10067. {
  10068. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10069. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10070. return -1;
  10071. // 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
  10072. // Find the correct method
  10073. bool isConst = ctx->type.dataType.IsObjectConst();
  10074. asCArray<int> funcs;
  10075. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10076. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10077. {
  10078. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10079. if( func->name == opName &&
  10080. func->parameterTypes.GetLength() == 0 &&
  10081. (!isConst || func->IsReadOnly()) )
  10082. {
  10083. funcs.PushLast(func->id);
  10084. }
  10085. }
  10086. // Did we find the method?
  10087. if( funcs.GetLength() == 1 )
  10088. {
  10089. asCArray<asCExprContext *> args;
  10090. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10091. }
  10092. else if( funcs.GetLength() == 0 )
  10093. {
  10094. asCString str;
  10095. str = asCString(opName) + "()";
  10096. if( isConst )
  10097. str += " const";
  10098. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10099. Error(str, node);
  10100. ctx->type.SetDummy();
  10101. return -1;
  10102. }
  10103. else if( funcs.GetLength() > 1 )
  10104. {
  10105. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10106. PrintMatchingFuncs(funcs, node);
  10107. ctx->type.SetDummy();
  10108. return -1;
  10109. }
  10110. }
  10111. else if( op == ttPlus )
  10112. {
  10113. Error(TXT_ILLEGAL_OPERATION, node);
  10114. ctx->type.SetDummy();
  10115. return -1;
  10116. }
  10117. }
  10118. else if( op == ttPlus || op == ttMinus )
  10119. {
  10120. // This is only for primitives. Objects are treated in the above block
  10121. // Make sure the type is a math type
  10122. if( !(ctx->type.dataType.IsIntegerType() ||
  10123. ctx->type.dataType.IsUnsignedType() ||
  10124. ctx->type.dataType.IsFloatType() ||
  10125. ctx->type.dataType.IsDoubleType() ) )
  10126. {
  10127. Error(TXT_ILLEGAL_OPERATION, node);
  10128. return -1;
  10129. }
  10130. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10131. return -1;
  10132. asCDataType to = ctx->type.dataType;
  10133. if( ctx->type.dataType.IsUnsignedType() )
  10134. {
  10135. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10136. to = asCDataType::CreatePrimitive(ttInt8, false);
  10137. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10138. to = asCDataType::CreatePrimitive(ttInt16, false);
  10139. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10140. to = asCDataType::CreatePrimitive(ttInt, false);
  10141. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10142. to = asCDataType::CreatePrimitive(ttInt64, false);
  10143. else
  10144. {
  10145. Error(TXT_INVALID_TYPE, node);
  10146. return -1;
  10147. }
  10148. }
  10149. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10150. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  10151. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  10152. if( !ctx->type.isConstant )
  10153. {
  10154. ConvertToTempVariable(ctx);
  10155. asASSERT(!ctx->type.isLValue);
  10156. if( op == ttMinus )
  10157. {
  10158. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10159. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  10160. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10161. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  10162. else if( ctx->type.dataType.IsFloatType() )
  10163. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  10164. else if( ctx->type.dataType.IsDoubleType() )
  10165. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  10166. else
  10167. {
  10168. Error(TXT_ILLEGAL_OPERATION, node);
  10169. return -1;
  10170. }
  10171. return 0;
  10172. }
  10173. }
  10174. else
  10175. {
  10176. if( op == ttMinus )
  10177. {
  10178. if (ctx->type.dataType.IsIntegerType())
  10179. {
  10180. if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10181. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  10182. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10183. ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
  10184. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
  10185. ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
  10186. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
  10187. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  10188. }
  10189. else if( ctx->type.dataType.IsFloatType() )
  10190. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  10191. else if( ctx->type.dataType.IsDoubleType() )
  10192. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  10193. else
  10194. {
  10195. Error(TXT_ILLEGAL_OPERATION, node);
  10196. return -1;
  10197. }
  10198. return 0;
  10199. }
  10200. }
  10201. }
  10202. else if( op == ttNot )
  10203. {
  10204. // Allow value types to be converted to bool using 'bool opImplConv()'
  10205. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  10206. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  10207. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  10208. {
  10209. if( ctx->type.isConstant )
  10210. {
  10211. #if AS_SIZEOF_BOOL == 1
  10212. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10213. #else
  10214. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10215. #endif
  10216. return 0;
  10217. }
  10218. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10219. return -1;
  10220. ConvertToTempVariable(ctx);
  10221. asASSERT(!ctx->type.isLValue);
  10222. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10223. }
  10224. else
  10225. {
  10226. Error(TXT_ILLEGAL_OPERATION, node);
  10227. return -1;
  10228. }
  10229. }
  10230. else if( op == ttBitNot )
  10231. {
  10232. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10233. return -1;
  10234. asCDataType to = ctx->type.dataType;
  10235. if( ctx->type.dataType.IsIntegerType() )
  10236. {
  10237. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10238. to = asCDataType::CreatePrimitive(ttUInt8, false);
  10239. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10240. to = asCDataType::CreatePrimitive(ttUInt16, false);
  10241. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10242. to = asCDataType::CreatePrimitive(ttUInt, false);
  10243. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10244. to = asCDataType::CreatePrimitive(ttUInt64, false);
  10245. else
  10246. {
  10247. Error(TXT_INVALID_TYPE, node);
  10248. return -1;
  10249. }
  10250. }
  10251. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10252. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  10253. if( ctx->type.dataType.IsUnsignedType() )
  10254. {
  10255. if( ctx->type.isConstant )
  10256. {
  10257. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10258. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  10259. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10260. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  10261. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10262. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  10263. else
  10264. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  10265. return 0;
  10266. }
  10267. ConvertToTempVariable(ctx);
  10268. asASSERT(!ctx->type.isLValue);
  10269. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10270. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  10271. else
  10272. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  10273. }
  10274. else
  10275. {
  10276. Error(TXT_ILLEGAL_OPERATION, node);
  10277. return -1;
  10278. }
  10279. }
  10280. else if( op == ttInc || op == ttDec )
  10281. {
  10282. // Need a reference to the primitive that will be updated
  10283. // The result of this expression is the same reference as before
  10284. // Make sure the reference isn't a temporary variable
  10285. if( ctx->type.isTemporary )
  10286. {
  10287. Error(TXT_REF_IS_TEMP, node);
  10288. return -1;
  10289. }
  10290. if( ctx->type.dataType.IsReadOnly() )
  10291. {
  10292. Error(TXT_REF_IS_READ_ONLY, node);
  10293. return -1;
  10294. }
  10295. if( ctx->property_get || ctx->property_set )
  10296. {
  10297. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10298. return -1;
  10299. }
  10300. if( !ctx->type.isLValue )
  10301. {
  10302. Error(TXT_NOT_LVALUE, node);
  10303. return -1;
  10304. }
  10305. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10306. ConvertToReference(ctx);
  10307. else if( !ctx->type.dataType.IsReference() )
  10308. {
  10309. Error(TXT_NOT_VALID_REFERENCE, node);
  10310. return -1;
  10311. }
  10312. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10313. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10314. {
  10315. if( op == ttInc )
  10316. ctx->bc.Instr(asBC_INCi64);
  10317. else
  10318. ctx->bc.Instr(asBC_DECi64);
  10319. }
  10320. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  10321. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  10322. {
  10323. if( op == ttInc )
  10324. ctx->bc.Instr(asBC_INCi);
  10325. else
  10326. ctx->bc.Instr(asBC_DECi);
  10327. }
  10328. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10329. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10330. {
  10331. if( op == ttInc )
  10332. ctx->bc.Instr(asBC_INCi16);
  10333. else
  10334. ctx->bc.Instr(asBC_DECi16);
  10335. }
  10336. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10337. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10338. {
  10339. if( op == ttInc )
  10340. ctx->bc.Instr(asBC_INCi8);
  10341. else
  10342. ctx->bc.Instr(asBC_DECi8);
  10343. }
  10344. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  10345. {
  10346. if( op == ttInc )
  10347. ctx->bc.Instr(asBC_INCf);
  10348. else
  10349. ctx->bc.Instr(asBC_DECf);
  10350. }
  10351. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  10352. {
  10353. if( op == ttInc )
  10354. ctx->bc.Instr(asBC_INCd);
  10355. else
  10356. ctx->bc.Instr(asBC_DECd);
  10357. }
  10358. else
  10359. {
  10360. Error(TXT_ILLEGAL_OPERATION, node);
  10361. return -1;
  10362. }
  10363. }
  10364. else
  10365. {
  10366. // Unknown operator
  10367. asASSERT(false);
  10368. return -1;
  10369. }
  10370. return 0;
  10371. }
  10372. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  10373. {
  10374. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10375. {
  10376. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  10377. ctx->type.dataType.MakeReference(true);
  10378. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  10379. }
  10380. }
  10381. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10382. {
  10383. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  10384. }
  10385. // Returns:
  10386. // 1 = a valid match was found
  10387. // 0 = no matching symbols (or feature disabled)
  10388. // -1 = ambiguous getters or setters, i.e. multiple methods match symbol name and signature
  10389. // -2 = mismatching type for getter and setter
  10390. // -3 = processing error, e.g. out of memory
  10391. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10392. {
  10393. // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the
  10394. // getter/setter as it is done at the time of declaration. Should deprecate the other options
  10395. if( engine->ep.propertyAccessorMode == 0 )
  10396. {
  10397. // Property accessors have been disabled by the application
  10398. return 0;
  10399. }
  10400. int getId = 0, setId = 0;
  10401. asCString getName = "get_" + name;
  10402. asCString setName = "set_" + name;
  10403. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  10404. if( ctx->type.dataType.IsObject() )
  10405. {
  10406. asASSERT( ns == 0 );
  10407. // Don't look for property accessors in script classes if the script
  10408. // property accessors have been disabled by the application
  10409. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  10410. engine->ep.propertyAccessorMode >= 2 )
  10411. {
  10412. // Check if the object has any methods with the corresponding accessor name(s)
  10413. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10414. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10415. {
  10416. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  10417. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10418. continue;
  10419. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10420. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10421. {
  10422. if( getId == 0 )
  10423. getId = ot->methods[n];
  10424. else
  10425. {
  10426. if( multipleGetFuncs.GetLength() == 0 )
  10427. multipleGetFuncs.PushLast(getId);
  10428. multipleGetFuncs.PushLast(ot->methods[n]);
  10429. }
  10430. }
  10431. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10432. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10433. {
  10434. if( setId == 0 )
  10435. setId = ot->methods[n];
  10436. else
  10437. {
  10438. if( multipleSetFuncs.GetLength() == 0 )
  10439. multipleSetFuncs.PushLast(setId);
  10440. multipleSetFuncs.PushLast(ot->methods[n]);
  10441. }
  10442. }
  10443. }
  10444. }
  10445. }
  10446. else
  10447. {
  10448. asASSERT( ns != 0 );
  10449. // Look for appropriate global functions.
  10450. asCArray<int> funcs;
  10451. asUINT n;
  10452. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  10453. for( n = 0; n < funcs.GetLength(); n++ )
  10454. {
  10455. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10456. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10457. continue;
  10458. // Ignore script functions, if the application has disabled script defined property accessors
  10459. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10460. continue;
  10461. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10462. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10463. {
  10464. if( getId == 0 )
  10465. getId = funcs[n];
  10466. else
  10467. {
  10468. if( multipleGetFuncs.GetLength() == 0 )
  10469. multipleGetFuncs.PushLast(getId);
  10470. multipleGetFuncs.PushLast(funcs[n]);
  10471. }
  10472. }
  10473. }
  10474. funcs.SetLength(0);
  10475. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  10476. for( n = 0; n < funcs.GetLength(); n++ )
  10477. {
  10478. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10479. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10480. continue;
  10481. // Ignore script functions, if the application has disabled script defined property accessors
  10482. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10483. continue;
  10484. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10485. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10486. {
  10487. if( setId == 0 )
  10488. setId = funcs[n];
  10489. else
  10490. {
  10491. if( multipleSetFuncs.GetLength() == 0 )
  10492. multipleSetFuncs.PushLast(setId);
  10493. multipleSetFuncs.PushLast(funcs[n]);
  10494. }
  10495. }
  10496. }
  10497. }
  10498. bool isConst = ctx->type.dataType.IsObjectConst();
  10499. // Check for multiple matches
  10500. if( multipleGetFuncs.GetLength() > 0 )
  10501. {
  10502. // Filter the list by constness
  10503. FilterConst(multipleGetFuncs, !isConst);
  10504. if( multipleGetFuncs.GetLength() > 1 )
  10505. {
  10506. if (node)
  10507. {
  10508. asCString str;
  10509. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  10510. Error(str, node);
  10511. PrintMatchingFuncs(multipleGetFuncs, node);
  10512. }
  10513. return -1;
  10514. }
  10515. else
  10516. {
  10517. // The id may have changed
  10518. getId = multipleGetFuncs[0];
  10519. }
  10520. }
  10521. if( multipleSetFuncs.GetLength() > 0 )
  10522. {
  10523. // Filter the list by constness
  10524. FilterConst(multipleSetFuncs, !isConst);
  10525. if( multipleSetFuncs.GetLength() > 1 )
  10526. {
  10527. if (node)
  10528. {
  10529. asCString str;
  10530. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  10531. Error(str, node);
  10532. PrintMatchingFuncs(multipleSetFuncs, node);
  10533. }
  10534. return -1;
  10535. }
  10536. else
  10537. {
  10538. // The id may have changed
  10539. setId = multipleSetFuncs[0];
  10540. }
  10541. }
  10542. // Check for type compatibility between get and set accessor
  10543. if( getId && setId )
  10544. {
  10545. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  10546. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  10547. // It is permitted for a getter to return a handle and the setter to take a reference
  10548. int idx = (arg?1:0);
  10549. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  10550. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  10551. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  10552. {
  10553. if (node)
  10554. {
  10555. asCString str;
  10556. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  10557. Error(str, node);
  10558. asCArray<int> funcs;
  10559. funcs.PushLast(getId);
  10560. funcs.PushLast(setId);
  10561. PrintMatchingFuncs(funcs, node);
  10562. }
  10563. return -2;
  10564. }
  10565. }
  10566. // Check if we are within one of the accessors
  10567. int realGetId = getId;
  10568. int realSetId = setId;
  10569. if( outFunc->objectType && isThisAccess )
  10570. {
  10571. // The property accessors would be virtual functions, so we need to find the real implementation
  10572. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  10573. if( getFunc &&
  10574. getFunc->funcType == asFUNC_VIRTUAL &&
  10575. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  10576. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  10577. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  10578. if( setFunc &&
  10579. setFunc->funcType == asFUNC_VIRTUAL &&
  10580. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  10581. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  10582. }
  10583. // Avoid recursive call by not treating this as a property accessor call.
  10584. // This will also allow having the real property with the same name as the accessors.
  10585. if( (isThisAccess || outFunc->objectType == 0) &&
  10586. ((realGetId && realGetId == outFunc->id) ||
  10587. (realSetId && realSetId == outFunc->id)) )
  10588. {
  10589. getId = 0;
  10590. setId = 0;
  10591. }
  10592. if( getId || setId )
  10593. {
  10594. // Property accessors were found, but we don't know which is to be used yet, so
  10595. // we just prepare the bytecode for the method call, and then store the function ids
  10596. // so that the right one can be used when we get there.
  10597. ctx->property_get = getId;
  10598. ctx->property_set = setId;
  10599. bool isRefSafe = ctx->type.isRefSafe;
  10600. if( ctx->type.dataType.IsObject() )
  10601. {
  10602. // If the object is read-only then we need to remember that
  10603. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  10604. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  10605. ctx->property_const = true;
  10606. else
  10607. ctx->property_const = false;
  10608. // If the object is a handle then we need to remember that
  10609. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  10610. ctx->property_ref = ctx->type.dataType.IsReference();
  10611. }
  10612. // The setter's parameter type is used as the property type,
  10613. // unless only the getter is available
  10614. asCDataType dt;
  10615. if( setId )
  10616. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  10617. else
  10618. dt = builder->GetFunctionDescription(getId)->returnType;
  10619. // Just change the type, the context must still maintain information
  10620. // about previous variable offset and the indicator of temporary variable.
  10621. int offset = ctx->type.stackOffset;
  10622. bool isTemp = ctx->type.isTemporary;
  10623. ctx->type.Set(dt);
  10624. ctx->type.stackOffset = (short)offset;
  10625. ctx->type.isTemporary = isTemp;
  10626. ctx->exprNode = node;
  10627. // Remember if the object is safe, so the invocation of the property
  10628. // accessor doesn't needlessly make a safe copy of the handle
  10629. ctx->type.isRefSafe = isRefSafe;
  10630. // Store the argument for later use
  10631. if( arg )
  10632. {
  10633. ctx->property_arg = asNEW(asCExprContext)(engine);
  10634. if( ctx->property_arg == 0 )
  10635. {
  10636. // Out of memory
  10637. return -3;
  10638. }
  10639. MergeExprBytecodeAndType(ctx->property_arg, arg);
  10640. }
  10641. return 1;
  10642. }
  10643. // No accessor was found
  10644. return 0;
  10645. }
  10646. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  10647. {
  10648. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  10649. if( !ctx->property_set )
  10650. {
  10651. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  10652. return -1;
  10653. }
  10654. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  10655. // Make sure the arg match the property
  10656. asCArray<int> funcs;
  10657. funcs.PushLast(ctx->property_set);
  10658. asCArray<asCExprContext *> args;
  10659. if( ctx->property_arg )
  10660. args.PushLast(ctx->property_arg);
  10661. args.PushLast(arg);
  10662. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10663. if( funcs.GetLength() == 0 )
  10664. {
  10665. // MatchFunctions already reported the error
  10666. if( ctx->property_arg )
  10667. {
  10668. asDELETE(ctx->property_arg, asCExprContext);
  10669. ctx->property_arg = 0;
  10670. }
  10671. return -1;
  10672. }
  10673. if( func->objectType )
  10674. {
  10675. // Setup the context with the original type so the method call gets built correctly
  10676. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10677. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10678. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10679. // Don't allow the call if the object is read-only and the property accessor is not const
  10680. if( ctx->property_const && !func->IsReadOnly() )
  10681. {
  10682. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10683. asCArray<int> funcCandidates;
  10684. funcCandidates.PushLast(ctx->property_set);
  10685. PrintMatchingFuncs(funcCandidates, node);
  10686. }
  10687. }
  10688. // Call the accessor
  10689. int r = MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  10690. ctx->property_get = 0;
  10691. ctx->property_set = 0;
  10692. if( ctx->property_arg )
  10693. {
  10694. asDELETE(ctx->property_arg, asCExprContext);
  10695. ctx->property_arg = 0;
  10696. }
  10697. return r;
  10698. }
  10699. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  10700. {
  10701. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  10702. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  10703. // to support value types, since it would be a single call
  10704. // Compound assignment for indexed property accessors is not supported yet
  10705. if( lctx->property_arg != 0 )
  10706. {
  10707. // Process the property to free the memory
  10708. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10709. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  10710. return -1;
  10711. }
  10712. // Compound assignments require both get and set accessors
  10713. if( lctx->property_set == 0 || lctx->property_get == 0 )
  10714. {
  10715. // Process the property to free the memory
  10716. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10717. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  10718. return -1;
  10719. }
  10720. // Property accessors on value types (or scoped references types) are not supported since
  10721. // it is not possible to guarantee that the object will stay alive between the two calls
  10722. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  10723. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  10724. {
  10725. // Process the property to free the memory
  10726. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10727. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  10728. return -1;
  10729. }
  10730. // Translate the compound assignment to the corresponding dual operator
  10731. switch( op )
  10732. {
  10733. case ttAddAssign: op = ttPlus; break;
  10734. case ttSubAssign: op = ttMinus; break;
  10735. case ttMulAssign: op = ttStar; break;
  10736. case ttDivAssign: op = ttSlash; break;
  10737. case ttModAssign: op = ttPercent; break;
  10738. case ttPowAssign: op = ttStarStar; break;
  10739. case ttAndAssign: op = ttAmp; break;
  10740. case ttOrAssign: op = ttBitOr; break;
  10741. case ttXorAssign: op = ttBitXor; break;
  10742. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  10743. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  10744. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  10745. default: op = ttUnrecognizedToken; break;
  10746. }
  10747. if( op == ttUnrecognizedToken )
  10748. {
  10749. // Shouldn't happen
  10750. asASSERT(false);
  10751. // Process the property to free the memory
  10752. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10753. return -1;
  10754. }
  10755. asCExprContext before(engine);
  10756. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  10757. {
  10758. // Keep a reference to the object in a local variable
  10759. before.bc.AddCode(&lctx->bc);
  10760. asUINT len = reservedVariables.GetLength();
  10761. rctx->bc.GetVarsUsed(reservedVariables);
  10762. before.bc.GetVarsUsed(reservedVariables);
  10763. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  10764. int offset = AllocateVariable(dt, true);
  10765. reservedVariables.SetLength(len);
  10766. before.type.SetVariable(dt, offset, true);
  10767. if( lctx->property_ref )
  10768. before.bc.Instr(asBC_RDSPtr);
  10769. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  10770. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  10771. before.bc.Instr(asBC_PopPtr);
  10772. if( lctx->type.isTemporary )
  10773. {
  10774. // Add the release of the temporary variable as a deferred expression
  10775. asSDeferredParam deferred;
  10776. deferred.origExpr = 0;
  10777. deferred.argInOutFlags = asTM_INREF;
  10778. deferred.argNode = 0;
  10779. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  10780. before.deferredParams.PushLast(deferred);
  10781. }
  10782. // Update the left expression to use the local variable
  10783. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10784. lctx->type.stackOffset = (short)offset;
  10785. lctx->property_ref = true;
  10786. // Don't release the temporary variable too early
  10787. lctx->type.isTemporary = false;
  10788. ctx->bc.AddCode(&before.bc);
  10789. }
  10790. // Keep the original information on the property
  10791. asCExprContext llctx(engine);
  10792. llctx.type = lctx->type;
  10793. llctx.property_arg = lctx->property_arg;
  10794. llctx.property_const = lctx->property_const;
  10795. llctx.property_get = lctx->property_get;
  10796. llctx.property_handle = lctx->property_handle;
  10797. llctx.property_ref = lctx->property_ref;
  10798. llctx.property_set = lctx->property_set;
  10799. // Compile the dual operator using the get accessor
  10800. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  10801. // If we made a local variable to hold the reference it must be reused
  10802. if( before.type.stackOffset )
  10803. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  10804. // Compile the assignment using the set accessor
  10805. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  10806. MergeExprBytecodeAndType(ctx, &llctx);
  10807. if( before.type.stackOffset )
  10808. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  10809. asASSERT( ctx->deferredParams.GetLength() == 0 );
  10810. ctx->deferredParams = before.deferredParams;
  10811. ProcessDeferredParams(ctx);
  10812. return 0;
  10813. }
  10814. int asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  10815. {
  10816. // If no property accessor has been prepared then don't do anything
  10817. if( !ctx->property_get && !ctx->property_set )
  10818. return 0;
  10819. if( !ctx->property_get )
  10820. {
  10821. // Raise error on missing accessor
  10822. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  10823. return -1;
  10824. }
  10825. asCExprValue objType = ctx->type;
  10826. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  10827. // Make sure the arg match the property
  10828. asCArray<int> funcs;
  10829. funcs.PushLast(ctx->property_get);
  10830. asCArray<asCExprContext *> args;
  10831. if( ctx->property_arg )
  10832. args.PushLast(ctx->property_arg);
  10833. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10834. if( funcs.GetLength() == 0 )
  10835. {
  10836. // MatchFunctions already reported the error
  10837. if( ctx->property_arg )
  10838. {
  10839. asDELETE(ctx->property_arg, asCExprContext);
  10840. ctx->property_arg = 0;
  10841. }
  10842. return -1;
  10843. }
  10844. if( func->objectType )
  10845. {
  10846. // Setup the context with the original type so the method call gets built correctly
  10847. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10848. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10849. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10850. // Don't allow the call if the object is read-only and the property accessor is not const
  10851. if( ctx->property_const && !func->IsReadOnly() )
  10852. {
  10853. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10854. asCArray<int> funcCandidates;
  10855. funcCandidates.PushLast(ctx->property_get);
  10856. PrintMatchingFuncs(funcCandidates, node);
  10857. return -1;
  10858. }
  10859. }
  10860. // The explicit handle flag must be remembered
  10861. bool isExplicitHandle = ctx->type.isExplicitHandle;
  10862. // Call the accessor
  10863. int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  10864. if( isExplicitHandle )
  10865. ctx->type.isExplicitHandle = true;
  10866. // Clear the property get/set ids
  10867. ctx->property_get = 0;
  10868. ctx->property_set = 0;
  10869. if( ctx->property_arg )
  10870. {
  10871. asDELETE(ctx->property_arg, asCExprContext);
  10872. ctx->property_arg = 0;
  10873. }
  10874. return r;
  10875. }
  10876. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  10877. {
  10878. // Don't allow any postfix operators on expressions that take address of class method
  10879. if( ctx->IsClassMethod() )
  10880. {
  10881. Error(TXT_INVALID_OP_ON_METHOD, node);
  10882. return -1;
  10883. }
  10884. // Don't allow any operators on void expressions
  10885. if( ctx->IsVoidExpression() )
  10886. {
  10887. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10888. return -1;
  10889. }
  10890. // Check if the variable is initialized (if it indeed is a variable)
  10891. IsVariableInitialized(&ctx->type, node);
  10892. int op = node->tokenType;
  10893. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10894. {
  10895. const char *opName = 0;
  10896. switch( op )
  10897. {
  10898. case ttInc: opName = "opPostInc"; break;
  10899. case ttDec: opName = "opPostDec"; break;
  10900. }
  10901. if( opName )
  10902. {
  10903. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10904. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10905. return -1;
  10906. // 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
  10907. // Find the correct method
  10908. bool isConst = ctx->type.dataType.IsObjectConst();
  10909. asCArray<int> funcs;
  10910. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10911. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10912. {
  10913. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10914. if( func->name == opName &&
  10915. func->parameterTypes.GetLength() == 0 &&
  10916. (!isConst || func->IsReadOnly()) )
  10917. {
  10918. funcs.PushLast(func->id);
  10919. }
  10920. }
  10921. // Did we find the method?
  10922. if( funcs.GetLength() == 1 )
  10923. {
  10924. asCArray<asCExprContext *> args;
  10925. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10926. }
  10927. else if( funcs.GetLength() == 0 )
  10928. {
  10929. asCString str;
  10930. str = asCString(opName) + "()";
  10931. if( isConst )
  10932. str += " const";
  10933. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10934. Error(str, node);
  10935. ctx->type.SetDummy();
  10936. return -1;
  10937. }
  10938. else if( funcs.GetLength() > 1 )
  10939. {
  10940. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10941. PrintMatchingFuncs(funcs, node);
  10942. ctx->type.SetDummy();
  10943. return -1;
  10944. }
  10945. }
  10946. }
  10947. else if( op == ttInc || op == ttDec )
  10948. {
  10949. // Make sure the reference isn't a temporary variable
  10950. if( ctx->type.isTemporary )
  10951. {
  10952. Error(TXT_REF_IS_TEMP, node);
  10953. return -1;
  10954. }
  10955. if( ctx->type.dataType.IsReadOnly() )
  10956. {
  10957. Error(TXT_REF_IS_READ_ONLY, node);
  10958. return -1;
  10959. }
  10960. if( ctx->property_get || ctx->property_set )
  10961. {
  10962. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10963. return -1;
  10964. }
  10965. if( !ctx->type.isLValue )
  10966. {
  10967. Error(TXT_NOT_LVALUE, node);
  10968. return -1;
  10969. }
  10970. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10971. ConvertToReference(ctx);
  10972. else if( !ctx->type.dataType.IsReference() )
  10973. {
  10974. Error(TXT_NOT_VALID_REFERENCE, node);
  10975. return -1;
  10976. }
  10977. // Copy the value to a temp before changing it
  10978. ConvertToTempVariable(ctx);
  10979. asASSERT(!ctx->type.isLValue);
  10980. // Increment the value pointed to by the reference still in the register
  10981. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  10982. if( ctx->type.dataType.IsDoubleType() )
  10983. {
  10984. iInc = asBC_INCd;
  10985. iDec = asBC_DECd;
  10986. }
  10987. else if( ctx->type.dataType.IsFloatType() )
  10988. {
  10989. iInc = asBC_INCf;
  10990. iDec = asBC_DECf;
  10991. }
  10992. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  10993. {
  10994. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10995. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10996. {
  10997. iInc = asBC_INCi16;
  10998. iDec = asBC_DECi16;
  10999. }
  11000. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  11001. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  11002. {
  11003. iInc = asBC_INCi8;
  11004. iDec = asBC_DECi8;
  11005. }
  11006. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  11007. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  11008. {
  11009. iInc = asBC_INCi64;
  11010. iDec = asBC_DECi64;
  11011. }
  11012. }
  11013. else
  11014. {
  11015. Error(TXT_ILLEGAL_OPERATION, node);
  11016. return -1;
  11017. }
  11018. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  11019. }
  11020. else if( op == ttDot )
  11021. {
  11022. if( node->firstChild->nodeType == snIdentifier )
  11023. {
  11024. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11025. return -1;
  11026. // Get the property name
  11027. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  11028. if( ctx->type.dataType.IsObject() )
  11029. {
  11030. // We need to look for get/set property accessors.
  11031. // If found, the context stores information on the get/set accessors
  11032. // until it is known which is to be used.
  11033. int r = 0;
  11034. if( node->next && node->next->tokenType == ttOpenBracket )
  11035. {
  11036. // The property accessor should take an index arg
  11037. asCExprContext dummyArg(engine);
  11038. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  11039. }
  11040. if( r == 0 )
  11041. r = FindPropertyAccessor(name, ctx, node, 0);
  11042. if( r != 0 )
  11043. return r;
  11044. if( !ctx->type.dataType.IsPrimitive() )
  11045. Dereference(ctx, true);
  11046. if( ctx->type.dataType.IsObjectHandle() )
  11047. {
  11048. // Convert the handle to a normal object
  11049. asCDataType dt = ctx->type.dataType;
  11050. dt.MakeHandle(false);
  11051. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  11052. // The handle may not have been an lvalue, but the dereferenced object is
  11053. ctx->type.isLValue = true;
  11054. }
  11055. bool isConst = ctx->type.dataType.IsObjectConst();
  11056. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  11057. if( prop )
  11058. {
  11059. // Is the property access allowed?
  11060. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  11061. {
  11062. asCString msg;
  11063. if( prop->isPrivate )
  11064. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  11065. else
  11066. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  11067. Error(msg, node);
  11068. }
  11069. // Adjust the pointer for composite member
  11070. // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property
  11071. if( prop->compositeOffset || prop->isCompositeIndirect )
  11072. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11073. if (prop->isCompositeIndirect)
  11074. ctx->bc.Instr(asBC_RDSPtr);
  11075. // Put the offset on the stack
  11076. // This must always be done even if the offset is 0 so the type info is stored
  11077. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11078. if( prop->type.IsReference() )
  11079. ctx->bc.Instr(asBC_RDSPtr);
  11080. // Reference to primitive must be stored in the temp register
  11081. if( prop->type.IsPrimitive() )
  11082. {
  11083. ctx->bc.Instr(asBC_PopRPtr);
  11084. }
  11085. // Keep information about temporary variables as deferred expression
  11086. if( ctx->type.isTemporary )
  11087. {
  11088. // Add the release of this reference, as a deferred expression
  11089. asSDeferredParam deferred;
  11090. deferred.origExpr = 0;
  11091. deferred.argInOutFlags = asTM_INREF;
  11092. deferred.argNode = 0;
  11093. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  11094. ctx->deferredParams.PushLast(deferred);
  11095. }
  11096. // Set the new type and make sure it is not treated as a variable anymore
  11097. ctx->type.dataType = prop->type;
  11098. ctx->type.dataType.MakeReference(true);
  11099. ctx->type.isVariable = false;
  11100. ctx->type.isTemporary = false;
  11101. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  11102. {
  11103. // Objects that are members are not references
  11104. ctx->type.dataType.MakeReference(false);
  11105. // The object is safe (life time guaranteed) if the parent object is also safe
  11106. }
  11107. else if (ctx->type.dataType.IsObjectHandle())
  11108. {
  11109. // A object accessed through a handle cannot be considered safe,
  11110. // as it can be cleared at any time
  11111. ctx->type.isRefSafe = false;
  11112. }
  11113. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  11114. }
  11115. else
  11116. {
  11117. // If the name is not a property, the compiler must check if the name matches
  11118. // a method, which can be used for constructing delegates
  11119. asIScriptFunction *func = 0;
  11120. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11121. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  11122. {
  11123. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  11124. {
  11125. func = engine->scriptFunctions[ot->methods[n]];
  11126. break;
  11127. }
  11128. }
  11129. if( func )
  11130. {
  11131. // An object method was found. Keep the name of the method in the expression, but
  11132. // don't actually modify the bytecode at this point since it is not yet known what
  11133. // the method will be used for, or even what overloaded method should be used.
  11134. ctx->methodName = name;
  11135. }
  11136. else
  11137. {
  11138. asCString str;
  11139. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11140. Error(str, node);
  11141. return -1;
  11142. }
  11143. }
  11144. }
  11145. else
  11146. {
  11147. asCString str;
  11148. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11149. Error(str, node);
  11150. return -1;
  11151. }
  11152. }
  11153. else
  11154. {
  11155. // Make sure it is an object we are accessing
  11156. if( !ctx->type.dataType.IsObject() )
  11157. {
  11158. asCString str;
  11159. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11160. Error(str, node);
  11161. return -1;
  11162. }
  11163. // Process the get property accessor
  11164. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11165. return -1;
  11166. // Compile function call
  11167. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  11168. if( r < 0 ) return r;
  11169. }
  11170. }
  11171. else if( op == ttOpenBracket )
  11172. {
  11173. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  11174. // then we should use that instead of processing it now. If the argument has already been
  11175. // evaluated, then we should process the property accessor as a get access now as the new
  11176. // index operator is on the result of that accessor.
  11177. asCString propertyName;
  11178. asSNameSpace *ns = 0;
  11179. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  11180. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  11181. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  11182. {
  11183. // Determine the name of the property accessor
  11184. asCScriptFunction *func = 0;
  11185. if( ctx->property_get )
  11186. func = builder->GetFunctionDescription(ctx->property_get);
  11187. else
  11188. func = builder->GetFunctionDescription(ctx->property_set);
  11189. propertyName = func->GetName();
  11190. propertyName = propertyName.SubString(4);
  11191. // Set the original type of the expression so we can re-evaluate the property accessor
  11192. if( func->objectType )
  11193. {
  11194. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  11195. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  11196. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  11197. }
  11198. else
  11199. {
  11200. // Store the namespace where the function is declared
  11201. // so the same function can be found later
  11202. ctx->type.SetDummy();
  11203. ns = func->nameSpace;
  11204. }
  11205. ctx->property_get = ctx->property_set = 0;
  11206. if( ctx->property_arg )
  11207. {
  11208. asDELETE(ctx->property_arg, asCExprContext);
  11209. ctx->property_arg = 0;
  11210. }
  11211. }
  11212. else
  11213. {
  11214. if( !ctx->type.dataType.IsObject() )
  11215. {
  11216. asCString str;
  11217. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11218. Error(str, node);
  11219. return -1;
  11220. }
  11221. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11222. return -1;
  11223. }
  11224. // Compile the expression
  11225. bool isOK = true;
  11226. asCArray<asCExprContext *> args;
  11227. asCArray<asSNamedArgument> namedArgs;
  11228. asASSERT( node->firstChild->nodeType == snArgList );
  11229. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  11230. {
  11231. // Check for the existence of the opIndex method
  11232. bool lookForProperty = true;
  11233. if( propertyName == "" )
  11234. {
  11235. bool isConst = ctx->type.dataType.IsObjectConst();
  11236. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11237. asCArray<int> funcs;
  11238. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  11239. if( funcs.GetLength() > 0 )
  11240. {
  11241. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  11242. lookForProperty = false;
  11243. // Determine which of opIndex methods that match
  11244. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  11245. if( funcs.GetLength() != 1 )
  11246. {
  11247. // The error has already been reported by MatchFunctions
  11248. isOK = false;
  11249. }
  11250. else
  11251. {
  11252. // Add the default values for arguments not explicitly supplied
  11253. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  11254. if( r < 0 )
  11255. isOK = false;
  11256. else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 )
  11257. isOK = false;
  11258. }
  11259. }
  11260. }
  11261. if( lookForProperty && isOK )
  11262. {
  11263. if( args.GetLength() != 1 )
  11264. {
  11265. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  11266. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  11267. isOK = false;
  11268. }
  11269. else
  11270. {
  11271. Dereference(ctx, true);
  11272. asCExprContext lctx(engine);
  11273. MergeExprBytecodeAndType(&lctx, ctx);
  11274. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  11275. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  11276. if (r == 0)
  11277. {
  11278. asCString str;
  11279. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11280. Error(str, node);
  11281. isOK = false;
  11282. }
  11283. else if (r < 0)
  11284. isOK = false;
  11285. if (isOK)
  11286. MergeExprBytecodeAndType(ctx, &lctx);
  11287. }
  11288. }
  11289. }
  11290. else
  11291. isOK = false;
  11292. // Cleanup
  11293. for( asUINT n = 0; n < args.GetLength(); n++ )
  11294. if( args[n] )
  11295. {
  11296. asDELETE(args[n], asCExprContext);
  11297. }
  11298. if( !isOK )
  11299. return -1;
  11300. }
  11301. else if( op == ttOpenParanthesis )
  11302. {
  11303. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  11304. // Make sure the expression is a funcdef or an object that may have opCall methods
  11305. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  11306. {
  11307. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  11308. return -1;
  11309. }
  11310. // Compile arguments
  11311. bool isOK = true;
  11312. asCArray<asCExprContext *> args;
  11313. asCArray<asSNamedArgument> namedArgs;
  11314. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  11315. {
  11316. // Match arguments with the funcdef
  11317. asCArray<int> funcs;
  11318. if( ctx->type.dataType.IsFuncdef() )
  11319. {
  11320. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  11321. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  11322. }
  11323. else
  11324. {
  11325. bool isConst = ctx->type.dataType.IsObjectConst();
  11326. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  11327. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  11328. }
  11329. if( funcs.GetLength() != 1 )
  11330. {
  11331. // The error was reported by MatchFunctions()
  11332. // Dummy value
  11333. ctx->type.SetDummy();
  11334. }
  11335. else
  11336. {
  11337. // Add the default values for arguments not explicitly supplied
  11338. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  11339. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  11340. // is it enough to make sure it is in a local variable?
  11341. // For function pointer we must guarantee that the function is safe, i.e.
  11342. // by first storing the function pointer in a local variable (if it isn't already in one)
  11343. if( r == asSUCCESS )
  11344. {
  11345. Dereference(ctx, true);
  11346. if( ctx->type.dataType.IsFuncdef() )
  11347. {
  11348. if( !ctx->type.isVariable )
  11349. ConvertToVariable(ctx);
  11350. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  11351. ctx->bc.Instr(asBC_PopPtr);
  11352. }
  11353. r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  11354. if( r < 0 )
  11355. isOK = false;
  11356. }
  11357. else
  11358. isOK = false;
  11359. }
  11360. }
  11361. else
  11362. ctx->type.SetDummy();
  11363. // Cleanup
  11364. for( asUINT n = 0; n < args.GetLength(); n++ )
  11365. if( args[n] )
  11366. {
  11367. asDELETE(args[n], asCExprContext);
  11368. }
  11369. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  11370. if( namedArgs[n].ctx )
  11371. {
  11372. asDELETE(namedArgs[n].ctx, asCExprContext);
  11373. }
  11374. if( !isOK )
  11375. return -1;
  11376. }
  11377. return 0;
  11378. }
  11379. int asCCompiler::GetPrecedence(asCScriptNode *op)
  11380. {
  11381. // x ** y
  11382. // x * y, x / y, x % y
  11383. // x + y, x - y
  11384. // x <= y, x < y, x >= y, x > y
  11385. // x = =y, x != y, x xor y, x is y, x !is y
  11386. // x and y
  11387. // x or y
  11388. // The following are not used in this function,
  11389. // but should have lower precedence than the above
  11390. // x ? y : z
  11391. // x = y
  11392. // The expression term have the highest precedence
  11393. if( op->nodeType == snExprTerm )
  11394. return 1;
  11395. // Evaluate operators by token
  11396. int tokenType = op->tokenType;
  11397. if( tokenType == ttStarStar )
  11398. return 0;
  11399. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  11400. return -1;
  11401. if( tokenType == ttPlus || tokenType == ttMinus )
  11402. return -2;
  11403. if( tokenType == ttBitShiftLeft ||
  11404. tokenType == ttBitShiftRight ||
  11405. tokenType == ttBitShiftRightArith )
  11406. return -3;
  11407. if( tokenType == ttAmp )
  11408. return -4;
  11409. if( tokenType == ttBitXor )
  11410. return -5;
  11411. if( tokenType == ttBitOr )
  11412. return -6;
  11413. if( tokenType == ttLessThanOrEqual ||
  11414. tokenType == ttLessThan ||
  11415. tokenType == ttGreaterThanOrEqual ||
  11416. tokenType == ttGreaterThan )
  11417. return -7;
  11418. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  11419. return -8;
  11420. if( tokenType == ttAnd )
  11421. return -9;
  11422. if( tokenType == ttOr )
  11423. return -10;
  11424. // Unknown operator
  11425. asASSERT(false);
  11426. return 0;
  11427. }
  11428. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11429. {
  11430. matches.SetLength(0);
  11431. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  11432. {
  11433. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  11434. // Does the function have arguments enough?
  11435. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  11436. continue;
  11437. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  11438. if( cost != -1 )
  11439. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  11440. }
  11441. return (asUINT)matches.GetLength();
  11442. }
  11443. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11444. {
  11445. // void expressions can match any out parameter, but nothing else
  11446. if( argExpr->IsVoidExpression() )
  11447. {
  11448. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  11449. return 0;
  11450. return -1;
  11451. }
  11452. // Anonymous init lists can only match parameters that can be initialized with a list
  11453. if (argExpr->IsAnonymousInitList())
  11454. {
  11455. if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) ||
  11456. desc->parameterTypes[paramNum].GetBehaviour() == 0 ||
  11457. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 )
  11458. {
  11459. return -1;
  11460. }
  11461. return 0;
  11462. }
  11463. // Can we make the match by implicit conversion?
  11464. asCExprContext ti(engine);
  11465. ti.type = argExpr->type;
  11466. ti.methodName = argExpr->methodName;
  11467. ti.enumValue = argExpr->enumValue;
  11468. ti.exprNode = argExpr->exprNode;
  11469. if( argExpr->type.dataType.IsPrimitive() )
  11470. ti.type.dataType.MakeReference(false);
  11471. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  11472. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  11473. allowObjectConstruct = false;
  11474. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  11475. // If the function parameter is an inout-reference then it must not be possible to call the
  11476. // function with an incorrect argument type, even though the type can normally be converted.
  11477. if( desc->parameterTypes[paramNum].IsReference() &&
  11478. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  11479. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  11480. {
  11481. // Observe, that the below checks are only necessary for when unsafe references have been
  11482. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  11483. // for these value types.
  11484. // Don't allow a primitive to be converted to a reference of another primitive type
  11485. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  11486. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  11487. {
  11488. asASSERT( engine->ep.allowUnsafeReferences );
  11489. return -1;
  11490. }
  11491. // Don't allow an enum to be converted to a reference of another enum type
  11492. if( desc->parameterTypes[paramNum].IsEnumType() &&
  11493. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  11494. {
  11495. asASSERT( engine->ep.allowUnsafeReferences );
  11496. return -1;
  11497. }
  11498. // Don't allow a non-handle expression to be converted to a reference to a handle
  11499. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  11500. !argExpr->type.dataType.IsObjectHandle() )
  11501. {
  11502. asASSERT( engine->ep.allowUnsafeReferences );
  11503. return -1;
  11504. }
  11505. // Don't allow a value type to be converted
  11506. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  11507. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  11508. {
  11509. asASSERT( engine->ep.allowUnsafeReferences );
  11510. return -1;
  11511. }
  11512. }
  11513. // How well does the argument match the function parameter?
  11514. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  11515. return cost;
  11516. // No match is available
  11517. return -1;
  11518. }
  11519. int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  11520. {
  11521. // Reference parameters whose value won't be used don't evaluate the expression
  11522. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  11523. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  11524. {
  11525. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  11526. asCExprContext *orig = asNEW(asCExprContext)(engine);
  11527. if( orig == 0 )
  11528. {
  11529. // Out of memory
  11530. return -1;
  11531. }
  11532. MergeExprBytecodeAndType(orig, arg);
  11533. arg->origExpr = orig;
  11534. }
  11535. int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  11536. if (r < 0)
  11537. return r;
  11538. // arg still holds the original expression for output parameters
  11539. ctx->bc.AddCode(&arg->bc);
  11540. return 0;
  11541. }
  11542. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  11543. {
  11544. DetermineSingleFunc(lctx, node);
  11545. DetermineSingleFunc(rctx, node);
  11546. ctx->exprNode = node;
  11547. // What type of operator is it?
  11548. if( token == ttUnrecognizedToken )
  11549. token = node->tokenType;
  11550. if( token == ttUnrecognizedToken )
  11551. {
  11552. // This happens when the compiler is inferring an assignment
  11553. // operation from another action, for example in preparing a value
  11554. // as a function argument
  11555. token = ttAssignment;
  11556. }
  11557. // boolean operators are not overloadable
  11558. if( token == ttAnd ||
  11559. token == ttOr ||
  11560. token == ttXor )
  11561. return false;
  11562. // Dual operators can also be implemented as class methods
  11563. if( token == ttEqual ||
  11564. token == ttNotEqual )
  11565. {
  11566. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11567. // Find the matching opEquals method
  11568. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11569. if( r == 0 )
  11570. {
  11571. // Try again by switching the order of the operands
  11572. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11573. }
  11574. if( r == 1 )
  11575. {
  11576. if( token == ttNotEqual )
  11577. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  11578. // Success, don't continue
  11579. return true;
  11580. }
  11581. else if( r < 0 )
  11582. {
  11583. // Compiler error, don't continue
  11584. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11585. return true;
  11586. }
  11587. }
  11588. if( token == ttEqual ||
  11589. token == ttNotEqual ||
  11590. token == ttLessThan ||
  11591. token == ttLessThanOrEqual ||
  11592. token == ttGreaterThan ||
  11593. token == ttGreaterThanOrEqual )
  11594. {
  11595. bool swappedOrder = false;
  11596. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11597. // Find the matching opCmp method
  11598. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11599. if( r == 0 )
  11600. {
  11601. // Try again by switching the order of the operands
  11602. swappedOrder = true;
  11603. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11604. }
  11605. if( r == 1 )
  11606. {
  11607. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11608. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11609. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  11610. if( token == ttEqual )
  11611. ctx->bc.Instr(asBC_TZ);
  11612. else if( token == ttNotEqual )
  11613. ctx->bc.Instr(asBC_TNZ);
  11614. else if( (token == ttLessThan && !swappedOrder) ||
  11615. (token == ttGreaterThan && swappedOrder) )
  11616. ctx->bc.Instr(asBC_TS);
  11617. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  11618. (token == ttGreaterThanOrEqual && swappedOrder) )
  11619. ctx->bc.Instr(asBC_TNP);
  11620. else if( (token == ttGreaterThan && !swappedOrder) ||
  11621. (token == ttLessThan && swappedOrder) )
  11622. ctx->bc.Instr(asBC_TP);
  11623. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  11624. (token == ttLessThanOrEqual && swappedOrder) )
  11625. ctx->bc.Instr(asBC_TNS);
  11626. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11627. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  11628. // Success, don't continue
  11629. return true;
  11630. }
  11631. else if( r < 0 )
  11632. {
  11633. // Compiler error, don't continue
  11634. #if AS_SIZEOF_BOOL == 1
  11635. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11636. #else
  11637. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11638. #endif
  11639. return true;
  11640. }
  11641. }
  11642. // The rest of the operators are not commutative, and doesn't require specific return type
  11643. const char *op = 0, *op_r = 0;
  11644. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11645. {
  11646. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  11647. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  11648. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  11649. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  11650. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  11651. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  11652. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  11653. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  11654. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  11655. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  11656. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  11657. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  11658. }
  11659. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  11660. if( op && op_r )
  11661. {
  11662. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11663. // Find the matching operator method
  11664. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  11665. if( r == 0 )
  11666. {
  11667. // Try again by switching the order of the operands, and using the reversed operator
  11668. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  11669. }
  11670. if( r == 1 )
  11671. {
  11672. // Success, don't continue
  11673. return true;
  11674. }
  11675. else if( r < 0 )
  11676. {
  11677. // Compiler error, don't continue
  11678. ctx->type.SetDummy();
  11679. return true;
  11680. }
  11681. }
  11682. // Assignment operators
  11683. op = 0;
  11684. if( isHandle )
  11685. {
  11686. // Only asOBJ_ASHANDLE types can get here
  11687. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  11688. asASSERT( token == ttAssignment );
  11689. if( token == ttAssignment )
  11690. op = "opHndlAssign";
  11691. }
  11692. else
  11693. {
  11694. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11695. {
  11696. case ttAssignment: op = "opAssign"; break;
  11697. case ttAddAssign: op = "opAddAssign"; break;
  11698. case ttSubAssign: op = "opSubAssign"; break;
  11699. case ttMulAssign: op = "opMulAssign"; break;
  11700. case ttDivAssign: op = "opDivAssign"; break;
  11701. case ttModAssign: op = "opModAssign"; break;
  11702. case ttPowAssign: op = "opPowAssign"; break;
  11703. case ttOrAssign: op = "opOrAssign"; break;
  11704. case ttAndAssign: op = "opAndAssign"; break;
  11705. case ttXorAssign: op = "opXorAssign"; break;
  11706. case ttShiftLeftAssign: op = "opShlAssign"; break;
  11707. case ttShiftRightLAssign: op = "opShrAssign"; break;
  11708. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  11709. }
  11710. }
  11711. if( op )
  11712. {
  11713. if( builder->engine->ep.disallowValueAssignForRefType &&
  11714. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  11715. {
  11716. if( token == ttAssignment )
  11717. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  11718. else
  11719. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  11720. // Set a dummy output
  11721. ctx->type.Set(lctx->type.dataType);
  11722. return true;
  11723. }
  11724. // TODO: Shouldn't accept const lvalue with the assignment operators
  11725. // Find the matching operator method
  11726. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  11727. if( r == 1 )
  11728. {
  11729. // Success, don't continue
  11730. return true;
  11731. }
  11732. else if( r < 0 )
  11733. {
  11734. // Compiler error, don't continue
  11735. ctx->type.SetDummy();
  11736. return true;
  11737. }
  11738. }
  11739. // No suitable operator was found
  11740. return false;
  11741. }
  11742. // Returns negative on compile error
  11743. // zero on no matching operator
  11744. // one on matching operator
  11745. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  11746. {
  11747. // Find the matching method
  11748. if( lctx->type.dataType.IsObject() &&
  11749. (!lctx->type.isExplicitHandle ||
  11750. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) &&
  11751. !lctx->type.IsNullConstant() )
  11752. {
  11753. asUINT n;
  11754. // Is the left value a const?
  11755. bool isConst = lctx->type.dataType.IsObjectConst();
  11756. asCArray<int> funcs;
  11757. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  11758. asASSERT(ot);
  11759. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  11760. {
  11761. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11762. asASSERT( func );
  11763. if( func && func->name == methodName &&
  11764. (!specificReturn || func->returnType == returnType) &&
  11765. func->parameterTypes.GetLength() == 1 &&
  11766. (!isConst || func->IsReadOnly()) )
  11767. {
  11768. // Make sure the method is accessible by the module
  11769. if( builder->module->m_accessMask & func->accessMask )
  11770. {
  11771. funcs.PushLast(func->id);
  11772. }
  11773. }
  11774. }
  11775. // Which is the best matching function?
  11776. asCArray<asSOverloadCandidate> tempFuncs;
  11777. MatchArgument(funcs, tempFuncs, rctx, 0);
  11778. // Find the lowest cost operator(s)
  11779. asCArray<int> ops;
  11780. asUINT bestCost = asUINT(-1);
  11781. for( n = 0; n < tempFuncs.GetLength(); ++n )
  11782. {
  11783. asUINT cost = tempFuncs[n].cost;
  11784. if( cost < bestCost )
  11785. {
  11786. ops.SetLength(0);
  11787. bestCost = cost;
  11788. }
  11789. if( cost == bestCost )
  11790. ops.PushLast(tempFuncs[n].funcId);
  11791. }
  11792. // If the object is not const, then we need to prioritize non-const methods
  11793. if( !isConst )
  11794. FilterConst(ops);
  11795. // Did we find an operator?
  11796. if( ops.GetLength() == 1 )
  11797. {
  11798. // Reserve the variables used in the right expression so the new temporary
  11799. // variable allocated for the left operand isn't accidentally overwritten.
  11800. int l = int(reservedVariables.GetLength());
  11801. rctx->bc.GetVarsUsed(reservedVariables);
  11802. // Process the lctx expression as get accessor
  11803. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  11804. return -1;
  11805. reservedVariables.SetLength(l);
  11806. asCExprContext tmpCtx(engine);
  11807. if (leftToRight)
  11808. {
  11809. // Make sure lctx is in fact a variable. If it is a reference there is no
  11810. // guarantee that the reference will stay alive throughout the evaluation of rctx
  11811. if (!lctx->type.isVariable)
  11812. {
  11813. // Reserve the variables used in the right expression so the new temporary
  11814. // variable allocated for the left operand isn't accidentally overwritten.
  11815. l = int(reservedVariables.GetLength());
  11816. rctx->bc.GetVarsUsed(reservedVariables);
  11817. if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
  11818. {
  11819. // If the application allows unsafe references, then it is not necessary to
  11820. // make a copy of the object, just store the reference as a local variable
  11821. // Allocate a temporary variable as reference to the type
  11822. asCDataType dt = lctx->type.dataType;
  11823. dt.MakeReference(true);
  11824. int offset = AllocateVariable(dt, true, false, true);
  11825. Dereference(lctx, true);
  11826. // Copy the pointer to the temporary variable
  11827. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11828. if (lctx->type.dataType.IsFuncdef())
  11829. lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11830. else
  11831. lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo());
  11832. lctx->type.SetVariable(dt, offset, true);
  11833. }
  11834. else
  11835. {
  11836. if (lctx->type.dataType.SupportHandles())
  11837. lctx->type.dataType.MakeHandle(true);
  11838. PrepareTemporaryVariable(node, lctx);
  11839. }
  11840. reservedVariables.SetLength(l);
  11841. }
  11842. // Move the bytecode for the left operand to a temporary context
  11843. // so we can later make sure this is computed first
  11844. tmpCtx.bc.AddCode(&lctx->bc);
  11845. tmpCtx.bc.Instr(asBC_PopPtr);
  11846. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  11847. // This will be placed after rctx by MakeFunctionCall below
  11848. lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
  11849. // Implicitly dereference handle parameters sent by reference
  11850. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  11851. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  11852. lctx->bc.Instr(asBC_RDSPtr);
  11853. }
  11854. else
  11855. {
  11856. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  11857. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  11858. asCArray<int> usedVars;
  11859. lctx->bc.GetVarsUsed(usedVars);
  11860. asUINT oldReservedVars = reservedVariables.GetLength();
  11861. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  11862. {
  11863. if (rctx->deferredParams[n].argType.isTemporary &&
  11864. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  11865. {
  11866. if (reservedVariables.GetLength() == oldReservedVars)
  11867. reservedVariables.Concatenate(usedVars);
  11868. // Allocate a new variable for the deferred argument
  11869. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  11870. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  11871. rctx->deferredParams[n].argType.stackOffset = short(offset);
  11872. rctx->bc.ExchangeVar(oldVar, offset);
  11873. ReleaseTemporaryVariable(oldVar, 0);
  11874. }
  11875. }
  11876. reservedVariables.SetLength(oldReservedVars);
  11877. }
  11878. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  11879. asCArray<asCExprContext *> args;
  11880. args.PushLast(rctx);
  11881. MergeExprBytecode(ctx, lctx);
  11882. ctx->type = lctx->type;
  11883. if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 )
  11884. return -1;
  11885. // Rearrange the bytecode so the left argument is computed first
  11886. if (leftToRight)
  11887. {
  11888. tmpCtx.bc.AddCode(&ctx->bc);
  11889. ctx->bc.AddCode(&tmpCtx.bc);
  11890. }
  11891. // Found matching operator
  11892. return 1;
  11893. }
  11894. else if( ops.GetLength() > 1 )
  11895. {
  11896. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11897. PrintMatchingFuncs(ops, node);
  11898. ctx->type.SetDummy();
  11899. // Compiler error
  11900. return -1;
  11901. }
  11902. }
  11903. // No matching operator
  11904. return 0;
  11905. }
  11906. int asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  11907. {
  11908. if( objectType )
  11909. Dereference(ctx, true);
  11910. // Store the expression node for error reporting
  11911. if( ctx->exprNode == 0 )
  11912. ctx->exprNode = node;
  11913. asCByteCode objBC(engine);
  11914. objBC.AddCode(&ctx->bc);
  11915. int r = PrepareFunctionCall(funcId, &ctx->bc, args);
  11916. if (r < 0)
  11917. return r;
  11918. // Verify if any of the args variable offsets are used in the other code.
  11919. // If they are exchange the offset for a new one
  11920. asUINT n;
  11921. for( n = 0; n < args.GetLength(); n++ )
  11922. {
  11923. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  11924. {
  11925. // Release the current temporary variable
  11926. ReleaseTemporaryVariable(args[n]->type, 0);
  11927. asCDataType dt = args[n]->type.dataType;
  11928. dt.MakeReference(false);
  11929. int l = int(reservedVariables.GetLength());
  11930. objBC.GetVarsUsed(reservedVariables);
  11931. ctx->bc.GetVarsUsed(reservedVariables);
  11932. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  11933. reservedVariables.SetLength(l);
  11934. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  11935. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  11936. args[n]->type.stackOffset = (short)newOffset;
  11937. args[n]->type.isTemporary = true;
  11938. args[n]->type.isVariable = true;
  11939. }
  11940. }
  11941. // If the function will return a value type on the stack, then we must allocate space
  11942. // for that here and push the address on the stack as a hidden argument to the function
  11943. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  11944. if( func->DoesReturnOnStack() )
  11945. {
  11946. asASSERT(!useVariable);
  11947. useVariable = true;
  11948. stackOffset = AllocateVariable(func->returnType, true);
  11949. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  11950. }
  11951. ctx->bc.AddCode(&objBC);
  11952. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  11953. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  11954. return 0;
  11955. }
  11956. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  11957. {
  11958. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  11959. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  11960. {
  11961. Error(TXT_INVALID_OP_ON_METHOD, node);
  11962. return -1;
  11963. }
  11964. // Don't allow any operators on void expressions
  11965. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  11966. {
  11967. Error(TXT_VOID_CANT_BE_OPERAND, node);
  11968. return -1;
  11969. }
  11970. if( op == ttUnrecognizedToken )
  11971. op = node->tokenType;
  11972. IsVariableInitialized(&lctx->type, node);
  11973. IsVariableInitialized(&rctx->type, node);
  11974. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  11975. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  11976. op == ttIs || op == ttNotIs )
  11977. {
  11978. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  11979. return 0;
  11980. }
  11981. else
  11982. {
  11983. // Compile an overloaded operator for the two operands
  11984. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  11985. return 0;
  11986. // If both operands are objects, then we shouldn't continue
  11987. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  11988. {
  11989. asCString str;
  11990. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11991. Error(str, node);
  11992. ctx->type.SetDummy();
  11993. return -1;
  11994. }
  11995. // Process the property get accessors (if any)
  11996. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  11997. return -1;
  11998. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  11999. return -1;
  12000. // Make sure we have two variables or constants
  12001. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  12002. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  12003. // Make sure lctx doesn't end up with a variable used in rctx
  12004. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  12005. {
  12006. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  12007. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  12008. ReleaseTemporaryVariable(offset, 0);
  12009. }
  12010. // Math operators
  12011. // + - * / % ** += -= *= /= %= **=
  12012. if( op == ttPlus || op == ttAddAssign ||
  12013. op == ttMinus || op == ttSubAssign ||
  12014. op == ttStar || op == ttMulAssign ||
  12015. op == ttSlash || op == ttDivAssign ||
  12016. op == ttPercent || op == ttModAssign ||
  12017. op == ttStarStar || op == ttPowAssign )
  12018. {
  12019. CompileMathOperator(node, lctx, rctx, ctx, op);
  12020. return 0;
  12021. }
  12022. // Bitwise operators
  12023. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  12024. if( op == ttAmp || op == ttAndAssign ||
  12025. op == ttBitOr || op == ttOrAssign ||
  12026. op == ttBitXor || op == ttXorAssign ||
  12027. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12028. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12029. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12030. {
  12031. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  12032. return 0;
  12033. }
  12034. // Comparison operators
  12035. // == != < > <= >=
  12036. if( op == ttEqual || op == ttNotEqual ||
  12037. op == ttLessThan || op == ttLessThanOrEqual ||
  12038. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  12039. {
  12040. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  12041. return 0;
  12042. }
  12043. // Boolean operators
  12044. // && || ^^
  12045. if( op == ttAnd || op == ttOr || op == ttXor )
  12046. {
  12047. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  12048. return 0;
  12049. }
  12050. }
  12051. asASSERT(false);
  12052. return -1;
  12053. }
  12054. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12055. {
  12056. int l = int(reservedVariables.GetLength());
  12057. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12058. ConvertToTempVariable(ctx);
  12059. reservedVariables.SetLength(l);
  12060. }
  12061. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  12062. {
  12063. // This is only used for primitive types and null handles
  12064. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  12065. ConvertToVariable(ctx);
  12066. if( !ctx->type.isTemporary )
  12067. {
  12068. if( ctx->type.dataType.IsPrimitive() )
  12069. {
  12070. // Copy the variable to a temporary variable
  12071. int offset = AllocateVariable(ctx->type.dataType, true);
  12072. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12073. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  12074. else
  12075. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  12076. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12077. }
  12078. else
  12079. {
  12080. // We should never get here
  12081. asASSERT(false);
  12082. }
  12083. }
  12084. }
  12085. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  12086. {
  12087. // We should never get here while the context is still an unprocessed property accessor
  12088. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  12089. int offset;
  12090. if( !ctx->type.isVariable &&
  12091. (ctx->type.dataType.IsObjectHandle() ||
  12092. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  12093. {
  12094. offset = AllocateVariable(ctx->type.dataType, true);
  12095. if( ctx->type.IsNullConstant() )
  12096. {
  12097. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  12098. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  12099. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  12100. }
  12101. else
  12102. {
  12103. Dereference(ctx, true);
  12104. // Copy the object handle to a variable
  12105. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12106. if( ctx->type.dataType.IsFuncdef() )
  12107. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  12108. else
  12109. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  12110. ctx->bc.Instr(asBC_PopPtr);
  12111. }
  12112. // As this is an object the reference must be placed on the stack
  12113. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12114. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12115. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12116. ctx->type.dataType.MakeHandle(true);
  12117. ctx->type.dataType.MakeReference(true);
  12118. }
  12119. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  12120. ctx->type.dataType.IsPrimitive() )
  12121. {
  12122. if( ctx->type.isConstant )
  12123. {
  12124. offset = AllocateVariable(ctx->type.dataType, true);
  12125. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12126. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  12127. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12128. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  12129. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  12130. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  12131. else
  12132. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  12133. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12134. return;
  12135. }
  12136. else
  12137. {
  12138. asASSERT(ctx->type.dataType.IsPrimitive());
  12139. asASSERT(ctx->type.dataType.IsReference());
  12140. ctx->type.dataType.MakeReference(false);
  12141. offset = AllocateVariable(ctx->type.dataType, true);
  12142. // Read the value from the address in the register directly into the variable
  12143. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12144. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  12145. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12146. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  12147. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12148. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  12149. else
  12150. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  12151. }
  12152. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12153. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12154. }
  12155. }
  12156. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12157. {
  12158. int l = int(reservedVariables.GetLength());
  12159. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12160. ConvertToVariable(ctx);
  12161. reservedVariables.SetLength(l);
  12162. }
  12163. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  12164. {
  12165. asCArray<int> funcs;
  12166. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  12167. if( ot )
  12168. {
  12169. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  12170. {
  12171. // Consider only implicit casts
  12172. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  12173. if( func->name == "opImplConv" &&
  12174. func->returnType.IsPrimitive() &&
  12175. func->parameterTypes.GetLength() == 0 )
  12176. funcs.PushLast(ot->methods[n]);
  12177. }
  12178. // Use the one with the highest precision
  12179. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  12180. while( funcs.GetLength() > 1 )
  12181. {
  12182. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  12183. int value1 = 11, value2 = 11;
  12184. for( asUINT i = 0; i < 10; i++ )
  12185. {
  12186. if( returnType == match[i] )
  12187. {
  12188. value1 = i;
  12189. break;
  12190. }
  12191. }
  12192. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  12193. {
  12194. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  12195. for( asUINT i = 0; i < 10; i++ )
  12196. {
  12197. if( returnType == match[i] )
  12198. {
  12199. value2 = i;
  12200. break;
  12201. }
  12202. }
  12203. if( value2 >= value1 )
  12204. {
  12205. // Remove this and continue searching
  12206. funcs.RemoveIndexUnordered(n--);
  12207. }
  12208. else
  12209. {
  12210. // Remove the first, and start over
  12211. funcs.RemoveIndexUnordered(0);
  12212. break;
  12213. }
  12214. }
  12215. }
  12216. // Do the conversion
  12217. if( funcs.GetLength() )
  12218. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  12219. }
  12220. }
  12221. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12222. {
  12223. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12224. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  12225. // If either operand is a non-primitive then use the primitive type
  12226. if( !lctx->type.dataType.IsPrimitive() )
  12227. {
  12228. int l = int(reservedVariables.GetLength());
  12229. rctx->bc.GetVarsUsed(reservedVariables);
  12230. ImplicitConvObjectToBestMathType(lctx, node);
  12231. reservedVariables.SetLength(l);
  12232. }
  12233. if( !rctx->type.dataType.IsPrimitive() )
  12234. {
  12235. int l = int(reservedVariables.GetLength());
  12236. lctx->bc.GetVarsUsed(reservedVariables);
  12237. ImplicitConvObjectToBestMathType(rctx, node);
  12238. reservedVariables.SetLength(l);
  12239. }
  12240. // Both types must now be primitives. Implicitly convert them so they match
  12241. asCDataType to;
  12242. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12243. to.SetTokenType(ttDouble);
  12244. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12245. to.SetTokenType(ttFloat);
  12246. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12247. {
  12248. // Convert to int64 if both are signed or if one is non-constant and signed
  12249. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12250. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12251. to.SetTokenType(ttInt64);
  12252. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12253. to.SetTokenType(ttUInt64);
  12254. else
  12255. to.SetTokenType(ttInt64);
  12256. }
  12257. else
  12258. {
  12259. // Convert to int32 if both are signed or if one is non-constant and signed
  12260. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12261. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12262. to.SetTokenType(ttInt);
  12263. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12264. to.SetTokenType(ttUInt);
  12265. else
  12266. to.SetTokenType(ttInt);
  12267. }
  12268. // If doing an operation with double constant and float variable, the constant should be converted to float
  12269. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12270. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12271. to.SetTokenType(ttFloat);
  12272. if( op == ttUnrecognizedToken )
  12273. op = node->tokenType;
  12274. // If integer division is disabled, convert to floating-point
  12275. if( engine->ep.disableIntegerDivision &&
  12276. (op == ttSlash || op == ttDivAssign) &&
  12277. (to.IsIntegerType() || to.IsUnsignedType()) )
  12278. {
  12279. // Use double to avoid losing precision when dividing with 32bit ints
  12280. // For 64bit ints there is unfortunately no greater type so with those
  12281. // there is still a risk of loosing precision
  12282. to.SetTokenType(ttDouble);
  12283. }
  12284. // Do the actual conversion
  12285. int l = int(reservedVariables.GetLength());
  12286. rctx->bc.GetVarsUsed(reservedVariables);
  12287. lctx->bc.GetVarsUsed(reservedVariables);
  12288. if( lctx->type.dataType.IsReference() )
  12289. ConvertToVariable(lctx);
  12290. if( rctx->type.dataType.IsReference() )
  12291. ConvertToVariable(rctx);
  12292. if( to.IsPrimitive() )
  12293. {
  12294. // ttStarStar allows an integer, right-hand operand and a double
  12295. // left-hand operand.
  12296. if( (op == ttStarStar || op == ttPowAssign) &&
  12297. lctx->type.dataType.IsDoubleType() &&
  12298. (rctx->type.dataType.IsIntegerType() ||
  12299. rctx->type.dataType.IsUnsignedType()) )
  12300. {
  12301. to.SetTokenType(ttInt);
  12302. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12303. to.SetTokenType(ttDouble);
  12304. }
  12305. else
  12306. {
  12307. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12308. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12309. }
  12310. }
  12311. reservedVariables.SetLength(l);
  12312. // Verify that the conversion was successful
  12313. if( !lctx->type.dataType.IsIntegerType() &&
  12314. !lctx->type.dataType.IsUnsignedType() &&
  12315. !lctx->type.dataType.IsFloatType() &&
  12316. !lctx->type.dataType.IsDoubleType() )
  12317. {
  12318. asCString str;
  12319. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12320. Error(str, node);
  12321. ctx->type.SetDummy();
  12322. return;
  12323. }
  12324. if( !rctx->type.dataType.IsIntegerType() &&
  12325. !rctx->type.dataType.IsUnsignedType() &&
  12326. !rctx->type.dataType.IsFloatType() &&
  12327. !rctx->type.dataType.IsDoubleType() )
  12328. {
  12329. asCString str;
  12330. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12331. Error(str, node);
  12332. ctx->type.SetDummy();
  12333. return;
  12334. }
  12335. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12336. // Verify if we are dividing with a constant zero
  12337. if( rctx->type.isConstant &&
  12338. (op == ttSlash || op == ttDivAssign ||
  12339. op == ttPercent || op == ttModAssign) &&
  12340. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  12341. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  12342. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  12343. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  12344. {
  12345. Error(TXT_DIVIDE_BY_ZERO, node);
  12346. }
  12347. if( !isConstant )
  12348. {
  12349. ConvertToVariableNotIn(lctx, rctx);
  12350. ConvertToVariableNotIn(rctx, lctx);
  12351. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12352. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12353. if( op == ttAddAssign || op == ttSubAssign ||
  12354. op == ttMulAssign || op == ttDivAssign ||
  12355. op == ttModAssign || op == ttPowAssign )
  12356. {
  12357. // Merge the operands in the different order so that they are evaluated correctly
  12358. MergeExprBytecode(ctx, rctx);
  12359. MergeExprBytecode(ctx, lctx);
  12360. // We must not process the deferred parameters yet, as
  12361. // it may overwrite the lvalue kept in the register
  12362. }
  12363. else
  12364. {
  12365. MergeExprBytecode(ctx, lctx);
  12366. MergeExprBytecode(ctx, rctx);
  12367. ProcessDeferredParams(ctx);
  12368. }
  12369. asEBCInstr instruction = asBC_ADDi;
  12370. if( lctx->type.dataType.IsIntegerType() ||
  12371. lctx->type.dataType.IsUnsignedType() )
  12372. {
  12373. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12374. {
  12375. if( op == ttPlus || op == ttAddAssign )
  12376. instruction = asBC_ADDi;
  12377. else if( op == ttMinus || op == ttSubAssign )
  12378. instruction = asBC_SUBi;
  12379. else if( op == ttStar || op == ttMulAssign )
  12380. instruction = asBC_MULi;
  12381. else if( op == ttSlash || op == ttDivAssign )
  12382. {
  12383. if( lctx->type.dataType.IsIntegerType() )
  12384. instruction = asBC_DIVi;
  12385. else
  12386. instruction = asBC_DIVu;
  12387. }
  12388. else if( op == ttPercent || op == ttModAssign )
  12389. {
  12390. if( lctx->type.dataType.IsIntegerType() )
  12391. instruction = asBC_MODi;
  12392. else
  12393. instruction = asBC_MODu;
  12394. }
  12395. else if( op == ttStarStar || op == ttPowAssign )
  12396. {
  12397. if( lctx->type.dataType.IsIntegerType() )
  12398. instruction = asBC_POWi;
  12399. else
  12400. instruction = asBC_POWu;
  12401. }
  12402. }
  12403. else
  12404. {
  12405. if( op == ttPlus || op == ttAddAssign )
  12406. instruction = asBC_ADDi64;
  12407. else if( op == ttMinus || op == ttSubAssign )
  12408. instruction = asBC_SUBi64;
  12409. else if( op == ttStar || op == ttMulAssign )
  12410. instruction = asBC_MULi64;
  12411. else if( op == ttSlash || op == ttDivAssign )
  12412. {
  12413. if( lctx->type.dataType.IsIntegerType() )
  12414. instruction = asBC_DIVi64;
  12415. else
  12416. instruction = asBC_DIVu64;
  12417. }
  12418. else if( op == ttPercent || op == ttModAssign )
  12419. {
  12420. if( lctx->type.dataType.IsIntegerType() )
  12421. instruction = asBC_MODi64;
  12422. else
  12423. instruction = asBC_MODu64;
  12424. }
  12425. else if( op == ttStarStar || op == ttPowAssign )
  12426. {
  12427. if( lctx->type.dataType.IsIntegerType() )
  12428. instruction = asBC_POWi64;
  12429. else
  12430. instruction = asBC_POWu64;
  12431. }
  12432. }
  12433. }
  12434. else if( lctx->type.dataType.IsFloatType() )
  12435. {
  12436. if( op == ttPlus || op == ttAddAssign )
  12437. instruction = asBC_ADDf;
  12438. else if( op == ttMinus || op == ttSubAssign )
  12439. instruction = asBC_SUBf;
  12440. else if( op == ttStar || op == ttMulAssign )
  12441. instruction = asBC_MULf;
  12442. else if( op == ttSlash || op == ttDivAssign )
  12443. instruction = asBC_DIVf;
  12444. else if( op == ttPercent || op == ttModAssign )
  12445. instruction = asBC_MODf;
  12446. else if( op == ttStarStar || op == ttPowAssign )
  12447. instruction = asBC_POWf;
  12448. }
  12449. else if( lctx->type.dataType.IsDoubleType() )
  12450. {
  12451. if( rctx->type.dataType.IsIntegerType() )
  12452. {
  12453. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12454. if( op == ttStarStar || op == ttPowAssign )
  12455. instruction = asBC_POWdi;
  12456. else
  12457. asASSERT(false); // Should not be possible
  12458. }
  12459. else
  12460. {
  12461. if( op == ttPlus || op == ttAddAssign )
  12462. instruction = asBC_ADDd;
  12463. else if( op == ttMinus || op == ttSubAssign )
  12464. instruction = asBC_SUBd;
  12465. else if( op == ttStar || op == ttMulAssign )
  12466. instruction = asBC_MULd;
  12467. else if( op == ttSlash || op == ttDivAssign )
  12468. instruction = asBC_DIVd;
  12469. else if( op == ttPercent || op == ttModAssign )
  12470. instruction = asBC_MODd;
  12471. else if( op == ttStarStar || op == ttPowAssign )
  12472. instruction = asBC_POWd;
  12473. }
  12474. }
  12475. else
  12476. {
  12477. // Shouldn't be possible
  12478. asASSERT(false);
  12479. }
  12480. // Do the operation
  12481. int a = AllocateVariable(lctx->type.dataType, true);
  12482. int b = lctx->type.stackOffset;
  12483. int c = rctx->type.stackOffset;
  12484. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12485. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12486. }
  12487. else
  12488. {
  12489. // Both values are constants
  12490. if( lctx->type.dataType.IsIntegerType() ||
  12491. lctx->type.dataType.IsUnsignedType() )
  12492. {
  12493. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12494. {
  12495. int v = 0;
  12496. if( op == ttPlus )
  12497. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  12498. else if( op == ttMinus )
  12499. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12500. else if( op == ttStar )
  12501. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  12502. else if( op == ttSlash )
  12503. {
  12504. // TODO: Should probably report an error, rather than silently convert the value to 0
  12505. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12506. v = 0;
  12507. else
  12508. if( lctx->type.dataType.IsIntegerType() )
  12509. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  12510. else
  12511. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  12512. }
  12513. else if( op == ttPercent )
  12514. {
  12515. // TODO: Should probably report an error, rather than silently convert the value to 0
  12516. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12517. v = 0;
  12518. else
  12519. if( lctx->type.dataType.IsIntegerType() )
  12520. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  12521. else
  12522. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  12523. }
  12524. else if( op == ttStarStar )
  12525. {
  12526. bool isOverflow;
  12527. if( lctx->type.dataType.IsIntegerType() )
  12528. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  12529. else
  12530. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  12531. if( isOverflow )
  12532. Error(TXT_POW_OVERFLOW, node);
  12533. }
  12534. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12535. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12536. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  12537. ctx->type.dataType.SetTokenType(ttInt);
  12538. }
  12539. else
  12540. {
  12541. asQWORD v = 0;
  12542. if( op == ttPlus )
  12543. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  12544. else if( op == ttMinus )
  12545. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12546. else if( op == ttStar )
  12547. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  12548. else if( op == ttSlash )
  12549. {
  12550. // TODO: Should probably report an error, rather than silently convert the value to 0
  12551. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12552. v = 0;
  12553. else
  12554. if( lctx->type.dataType.IsIntegerType() )
  12555. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  12556. else
  12557. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  12558. }
  12559. else if( op == ttPercent )
  12560. {
  12561. // TODO: Should probably report an error, rather than silently convert the value to 0
  12562. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12563. v = 0;
  12564. else
  12565. if( lctx->type.dataType.IsIntegerType() )
  12566. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  12567. else
  12568. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  12569. }
  12570. else if( op == ttStarStar )
  12571. {
  12572. bool isOverflow;
  12573. if( lctx->type.dataType.IsIntegerType() )
  12574. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  12575. else
  12576. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  12577. if( isOverflow )
  12578. Error(TXT_POW_OVERFLOW, node);
  12579. }
  12580. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12581. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12582. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  12583. ctx->type.dataType.SetTokenType(ttInt64);
  12584. }
  12585. }
  12586. else if( lctx->type.dataType.IsFloatType() )
  12587. {
  12588. float v = 0.0f;
  12589. if( op == ttPlus )
  12590. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  12591. else if( op == ttMinus )
  12592. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12593. else if( op == ttStar )
  12594. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  12595. else if( op == ttSlash )
  12596. {
  12597. if( rctx->type.GetConstantF() == 0 )
  12598. v = 0;
  12599. else
  12600. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  12601. }
  12602. else if( op == ttPercent )
  12603. {
  12604. if( rctx->type.GetConstantF() == 0 )
  12605. v = 0;
  12606. else
  12607. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12608. }
  12609. else if( op == ttStarStar )
  12610. {
  12611. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12612. if( v == HUGE_VAL )
  12613. Error(TXT_POW_OVERFLOW, node);
  12614. }
  12615. ctx->type.SetConstantF(lctx->type.dataType, v);
  12616. }
  12617. else if( lctx->type.dataType.IsDoubleType() )
  12618. {
  12619. double v = 0.0;
  12620. if( rctx->type.dataType.IsIntegerType() )
  12621. {
  12622. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12623. if( op == ttStarStar || op == ttPowAssign )
  12624. {
  12625. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  12626. if( v == HUGE_VAL )
  12627. Error(TXT_POW_OVERFLOW, node);
  12628. }
  12629. else
  12630. asASSERT(false); // Should not be possible
  12631. }
  12632. else
  12633. {
  12634. if( op == ttPlus )
  12635. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  12636. else if( op == ttMinus )
  12637. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12638. else if( op == ttStar )
  12639. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  12640. else if( op == ttSlash )
  12641. {
  12642. if( rctx->type.GetConstantD() == 0 )
  12643. v = 0;
  12644. else
  12645. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  12646. }
  12647. else if( op == ttPercent )
  12648. {
  12649. if( rctx->type.GetConstantD() == 0 )
  12650. v = 0;
  12651. else
  12652. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12653. }
  12654. else if( op == ttStarStar )
  12655. {
  12656. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12657. if( v == HUGE_VAL )
  12658. Error(TXT_POW_OVERFLOW, node);
  12659. }
  12660. }
  12661. ctx->type.SetConstantD(lctx->type.dataType, v);
  12662. }
  12663. else
  12664. {
  12665. // Shouldn't be possible
  12666. asASSERT(false);
  12667. }
  12668. }
  12669. }
  12670. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12671. {
  12672. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12673. if( op == ttUnrecognizedToken )
  12674. op = node->tokenType;
  12675. if( op == ttAmp || op == ttAndAssign ||
  12676. op == ttBitOr || op == ttOrAssign ||
  12677. op == ttBitXor || op == ttXorAssign )
  12678. {
  12679. // Also do not permit float/double to be implicitly converted to integer in this case
  12680. // as the user may think the result is a bitwise operation on the float value but it's not
  12681. if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType())
  12682. {
  12683. asCString str;
  12684. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12685. Error(str, node);
  12686. // Set an integer value and allow the compiler to continue
  12687. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12688. return;
  12689. }
  12690. if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType())
  12691. {
  12692. asCString str;
  12693. str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12694. Error(str, node);
  12695. // Set an integer value and allow the compiler to continue
  12696. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12697. return;
  12698. }
  12699. // Convert left hand operand to integer if it's not already one
  12700. asCDataType to;
  12701. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  12702. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12703. to.SetTokenType(ttInt64);
  12704. else
  12705. to.SetTokenType(ttInt);
  12706. // Do the actual conversion (keep sign/unsigned if possible)
  12707. int l = int(reservedVariables.GetLength());
  12708. rctx->bc.GetVarsUsed(reservedVariables);
  12709. if( lctx->type.dataType.IsUnsignedType() )
  12710. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12711. else
  12712. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12713. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12714. reservedVariables.SetLength(l);
  12715. // Verify that the conversion was successful
  12716. if( lctx->type.dataType != to )
  12717. {
  12718. asCString str;
  12719. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12720. Error(str, node);
  12721. }
  12722. // Convert right hand operand to same size as left hand
  12723. l = int(reservedVariables.GetLength());
  12724. lctx->bc.GetVarsUsed(reservedVariables);
  12725. if( rctx->type.dataType.IsUnsignedType() )
  12726. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12727. else
  12728. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12729. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12730. reservedVariables.SetLength(l);
  12731. if( rctx->type.dataType != to )
  12732. {
  12733. asCString str;
  12734. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12735. Error(str, node);
  12736. }
  12737. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12738. if( !isConstant )
  12739. {
  12740. ConvertToVariableNotIn(lctx, rctx);
  12741. ConvertToVariableNotIn(rctx, lctx);
  12742. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12743. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12744. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  12745. {
  12746. // Compound assignments execute the right hand value first
  12747. MergeExprBytecode(ctx, rctx);
  12748. MergeExprBytecode(ctx, lctx);
  12749. }
  12750. else
  12751. {
  12752. MergeExprBytecode(ctx, lctx);
  12753. MergeExprBytecode(ctx, rctx);
  12754. }
  12755. ProcessDeferredParams(ctx);
  12756. asEBCInstr instruction = asBC_BAND;
  12757. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12758. {
  12759. if( op == ttAmp || op == ttAndAssign )
  12760. instruction = asBC_BAND;
  12761. else if( op == ttBitOr || op == ttOrAssign )
  12762. instruction = asBC_BOR;
  12763. else if( op == ttBitXor || op == ttXorAssign )
  12764. instruction = asBC_BXOR;
  12765. }
  12766. else
  12767. {
  12768. if( op == ttAmp || op == ttAndAssign )
  12769. instruction = asBC_BAND64;
  12770. else if( op == ttBitOr || op == ttOrAssign )
  12771. instruction = asBC_BOR64;
  12772. else if( op == ttBitXor || op == ttXorAssign )
  12773. instruction = asBC_BXOR64;
  12774. }
  12775. // Do the operation
  12776. int a = AllocateVariable(lctx->type.dataType, true);
  12777. int b = lctx->type.stackOffset;
  12778. int c = rctx->type.stackOffset;
  12779. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12780. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12781. }
  12782. else
  12783. {
  12784. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12785. {
  12786. asQWORD v = 0;
  12787. if( op == ttAmp )
  12788. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  12789. else if( op == ttBitOr )
  12790. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  12791. else if( op == ttBitXor )
  12792. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  12793. // Remember the result
  12794. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12795. }
  12796. else
  12797. {
  12798. asDWORD v = 0;
  12799. if( op == ttAmp )
  12800. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  12801. else if( op == ttBitOr )
  12802. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  12803. else if( op == ttBitXor )
  12804. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  12805. // Remember the result
  12806. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12807. }
  12808. }
  12809. }
  12810. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12811. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12812. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12813. {
  12814. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  12815. // Also do not permit float/double to be implicitly converted to integer in this case
  12816. if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() )
  12817. {
  12818. asCString str;
  12819. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12820. Error(str, node);
  12821. // Set an integer value and allow the compiler to continue
  12822. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12823. return;
  12824. }
  12825. // Convert left hand operand to integer if it's not already one
  12826. asCDataType to = lctx->type.dataType;
  12827. if( lctx->type.dataType.IsUnsignedType() &&
  12828. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  12829. {
  12830. // Upgrade to 32bit
  12831. to = asCDataType::CreatePrimitive(ttUInt, false);
  12832. }
  12833. else if( !lctx->type.dataType.IsUnsignedType() )
  12834. {
  12835. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  12836. to = asCDataType::CreatePrimitive(ttInt64, false);
  12837. else
  12838. to = asCDataType::CreatePrimitive(ttInt, false);
  12839. }
  12840. // Do the actual conversion
  12841. int l = int(reservedVariables.GetLength());
  12842. rctx->bc.GetVarsUsed(reservedVariables);
  12843. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12844. reservedVariables.SetLength(l);
  12845. // Verify that the conversion was successful
  12846. if( lctx->type.dataType != to )
  12847. {
  12848. asCString str;
  12849. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12850. Error(str, node);
  12851. }
  12852. // Right operand must be 32bit uint
  12853. l = int(reservedVariables.GetLength());
  12854. lctx->bc.GetVarsUsed(reservedVariables);
  12855. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  12856. reservedVariables.SetLength(l);
  12857. if( !rctx->type.dataType.IsUnsignedType() )
  12858. {
  12859. asCString str;
  12860. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  12861. Error(str, node);
  12862. }
  12863. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12864. if( !isConstant )
  12865. {
  12866. ConvertToVariableNotIn(lctx, rctx);
  12867. ConvertToVariableNotIn(rctx, lctx);
  12868. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12869. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12870. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  12871. {
  12872. // Compound assignments execute the right hand value first
  12873. MergeExprBytecode(ctx, rctx);
  12874. MergeExprBytecode(ctx, lctx);
  12875. }
  12876. else
  12877. {
  12878. MergeExprBytecode(ctx, lctx);
  12879. MergeExprBytecode(ctx, rctx);
  12880. }
  12881. ProcessDeferredParams(ctx);
  12882. asEBCInstr instruction = asBC_BSLL;
  12883. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12884. {
  12885. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12886. instruction = asBC_BSLL;
  12887. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12888. instruction = asBC_BSRL;
  12889. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12890. instruction = asBC_BSRA;
  12891. }
  12892. else
  12893. {
  12894. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12895. instruction = asBC_BSLL64;
  12896. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12897. instruction = asBC_BSRL64;
  12898. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12899. instruction = asBC_BSRA64;
  12900. }
  12901. // Do the operation
  12902. int a = AllocateVariable(lctx->type.dataType, true);
  12903. int b = lctx->type.stackOffset;
  12904. int c = rctx->type.stackOffset;
  12905. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12906. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12907. }
  12908. else
  12909. {
  12910. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12911. {
  12912. asDWORD v = 0;
  12913. if( op == ttBitShiftLeft )
  12914. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  12915. else if( op == ttBitShiftRight )
  12916. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  12917. else if( op == ttBitShiftRightArith )
  12918. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  12919. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12920. }
  12921. else
  12922. {
  12923. asQWORD v = 0;
  12924. if( op == ttBitShiftLeft )
  12925. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  12926. else if( op == ttBitShiftRight )
  12927. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  12928. else if( op == ttBitShiftRightArith )
  12929. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  12930. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12931. }
  12932. }
  12933. }
  12934. }
  12935. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12936. {
  12937. // Both operands must be of the same type
  12938. // If either operand is a non-primitive then first convert them to the best number type
  12939. if( !lctx->type.dataType.IsPrimitive() )
  12940. {
  12941. int l = int(reservedVariables.GetLength());
  12942. rctx->bc.GetVarsUsed(reservedVariables);
  12943. ImplicitConvObjectToBestMathType(lctx, node);
  12944. reservedVariables.SetLength(l);
  12945. }
  12946. if( !rctx->type.dataType.IsPrimitive() )
  12947. {
  12948. int l = int(reservedVariables.GetLength());
  12949. lctx->bc.GetVarsUsed(reservedVariables);
  12950. ImplicitConvObjectToBestMathType(rctx, node);
  12951. reservedVariables.SetLength(l);
  12952. }
  12953. // Implicitly convert the operands to matching types
  12954. asCDataType to;
  12955. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12956. to.SetTokenType(ttDouble);
  12957. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12958. to.SetTokenType(ttFloat);
  12959. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12960. {
  12961. // Convert to int64 if both are signed or if one is non-constant and signed
  12962. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12963. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12964. to.SetTokenType(ttInt64);
  12965. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12966. to.SetTokenType(ttUInt64);
  12967. else
  12968. to.SetTokenType(ttInt64);
  12969. }
  12970. else
  12971. {
  12972. // Convert to int32 if both are signed or if one is non-constant and signed
  12973. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12974. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12975. to.SetTokenType(ttInt);
  12976. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12977. to.SetTokenType(ttUInt);
  12978. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  12979. to.SetTokenType(ttBool);
  12980. else
  12981. to.SetTokenType(ttInt);
  12982. }
  12983. // If doing an operation with double constant and float variable, the constant should be converted to float
  12984. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12985. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12986. to.SetTokenType(ttFloat);
  12987. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  12988. // Do we have a mismatch between the sign of the operand?
  12989. bool signMismatch = false;
  12990. for( int n = 0; !signMismatch && n < 2; n++ )
  12991. {
  12992. asCExprContext *opCtx = n ? rctx : lctx;
  12993. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  12994. {
  12995. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  12996. signMismatch = true;
  12997. if( opCtx->type.isConstant )
  12998. {
  12999. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  13000. {
  13001. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  13002. signMismatch = false;
  13003. }
  13004. else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
  13005. {
  13006. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  13007. signMismatch = false;
  13008. }
  13009. else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
  13010. {
  13011. if (!(opCtx->type.GetConstantW() & (1 << 15)))
  13012. signMismatch = false;
  13013. }
  13014. else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
  13015. {
  13016. if (!(opCtx->type.GetConstantB() & (1 << 7)))
  13017. signMismatch = false;
  13018. }
  13019. // It's not necessary to check for floats or double, because if
  13020. // it was then the types for the conversion will never be unsigned
  13021. }
  13022. }
  13023. }
  13024. // Check for signed/unsigned mismatch
  13025. if( signMismatch )
  13026. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  13027. // Attempt to resolve ambiguous enumerations
  13028. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  13029. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13030. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  13031. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13032. // Do the actual conversion
  13033. int l = int(reservedVariables.GetLength());
  13034. rctx->bc.GetVarsUsed(reservedVariables);
  13035. if( lctx->type.dataType.IsReference() )
  13036. ConvertToVariable(lctx);
  13037. if( rctx->type.dataType.IsReference() )
  13038. ConvertToVariable(rctx);
  13039. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13040. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13041. reservedVariables.SetLength(l);
  13042. // Verify that the conversion was successful
  13043. bool ok = true;
  13044. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13045. {
  13046. asCString str;
  13047. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13048. Error(str, node);
  13049. ok = false;
  13050. }
  13051. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13052. {
  13053. asCString str;
  13054. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13055. Error(str, node);
  13056. ok = false;
  13057. }
  13058. if( !ok )
  13059. {
  13060. // It wasn't possible to get two valid operands, so we just return
  13061. // a boolean result and let the compiler continue.
  13062. #if AS_SIZEOF_BOOL == 1
  13063. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13064. #else
  13065. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13066. #endif
  13067. return;
  13068. }
  13069. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13070. if( op == ttUnrecognizedToken )
  13071. op = node->tokenType;
  13072. if( !isConstant )
  13073. {
  13074. if( to.IsBooleanType() )
  13075. {
  13076. if( op == ttEqual || op == ttNotEqual )
  13077. {
  13078. // Must convert to temporary variable, because we are changing the value before comparison
  13079. ConvertToTempVariableNotIn(lctx, rctx);
  13080. ConvertToTempVariableNotIn(rctx, lctx);
  13081. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13082. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13083. // Make sure they are equal if not false
  13084. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  13085. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  13086. MergeExprBytecode(ctx, lctx);
  13087. MergeExprBytecode(ctx, rctx);
  13088. ProcessDeferredParams(ctx);
  13089. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13090. int b = lctx->type.stackOffset;
  13091. int c = rctx->type.stackOffset;
  13092. if( op == ttEqual )
  13093. {
  13094. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13095. ctx->bc.Instr(asBC_TZ);
  13096. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13097. }
  13098. else if( op == ttNotEqual )
  13099. {
  13100. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13101. ctx->bc.Instr(asBC_TNZ);
  13102. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13103. }
  13104. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13105. }
  13106. else
  13107. {
  13108. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13109. Error(TXT_ILLEGAL_OPERATION, node);
  13110. #if AS_SIZEOF_BOOL == 1
  13111. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  13112. #else
  13113. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  13114. #endif
  13115. }
  13116. }
  13117. else
  13118. {
  13119. ConvertToVariableNotIn(lctx, rctx);
  13120. ConvertToVariableNotIn(rctx, lctx);
  13121. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13122. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13123. MergeExprBytecode(ctx, lctx);
  13124. MergeExprBytecode(ctx, rctx);
  13125. ProcessDeferredParams(ctx);
  13126. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  13127. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13128. iCmp = asBC_CMPi;
  13129. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13130. iCmp = asBC_CMPu;
  13131. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13132. iCmp = asBC_CMPi64;
  13133. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13134. iCmp = asBC_CMPu64;
  13135. else if( lctx->type.dataType.IsFloatType() )
  13136. iCmp = asBC_CMPf;
  13137. else if( lctx->type.dataType.IsDoubleType() )
  13138. iCmp = asBC_CMPd;
  13139. else
  13140. asASSERT(false);
  13141. if( op == ttEqual )
  13142. iT = asBC_TZ;
  13143. else if( op == ttNotEqual )
  13144. iT = asBC_TNZ;
  13145. else if( op == ttLessThan )
  13146. iT = asBC_TS;
  13147. else if( op == ttLessThanOrEqual )
  13148. iT = asBC_TNP;
  13149. else if( op == ttGreaterThan )
  13150. iT = asBC_TP;
  13151. else if( op == ttGreaterThanOrEqual )
  13152. iT = asBC_TNS;
  13153. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13154. int b = lctx->type.stackOffset;
  13155. int c = rctx->type.stackOffset;
  13156. ctx->bc.InstrW_W(iCmp, b, c);
  13157. ctx->bc.Instr(iT);
  13158. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13159. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13160. }
  13161. }
  13162. else
  13163. {
  13164. if( to.IsBooleanType() )
  13165. {
  13166. if( op == ttEqual || op == ttNotEqual )
  13167. {
  13168. asDWORD lv, rv;
  13169. #if AS_SIZEOF_BOOL == 1
  13170. lv = lctx->type.GetConstantB();
  13171. rv = rctx->type.GetConstantB();
  13172. #else
  13173. lv = lctx->type.GetConstantDW();
  13174. rv = rctx->type.GetConstantDW();
  13175. #endif
  13176. // Make sure they are equal if not false
  13177. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  13178. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  13179. asDWORD v = 0;
  13180. if (op == ttEqual)
  13181. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13182. else if (op == ttNotEqual)
  13183. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13184. #if AS_SIZEOF_BOOL == 1
  13185. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  13186. #else
  13187. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  13188. #endif
  13189. }
  13190. else
  13191. {
  13192. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13193. Error(TXT_ILLEGAL_OPERATION, node);
  13194. }
  13195. }
  13196. else
  13197. {
  13198. int i = 0;
  13199. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13200. {
  13201. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  13202. if( v < 0 ) i = -1;
  13203. if( v > 0 ) i = 1;
  13204. }
  13205. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13206. {
  13207. asDWORD v1 = lctx->type.GetConstantDW();
  13208. asDWORD v2 = rctx->type.GetConstantDW();
  13209. if( v1 < v2 ) i = -1;
  13210. if( v1 > v2 ) i = 1;
  13211. }
  13212. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13213. {
  13214. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  13215. if( v < 0 ) i = -1;
  13216. if( v > 0 ) i = 1;
  13217. }
  13218. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13219. {
  13220. asQWORD v1 = lctx->type.GetConstantQW();
  13221. asQWORD v2 = rctx->type.GetConstantQW();
  13222. if( v1 < v2 ) i = -1;
  13223. if( v1 > v2 ) i = 1;
  13224. }
  13225. else if( lctx->type.dataType.IsFloatType() )
  13226. {
  13227. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  13228. if( v < 0 ) i = -1;
  13229. if( v > 0 ) i = 1;
  13230. }
  13231. else if( lctx->type.dataType.IsDoubleType() )
  13232. {
  13233. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  13234. if( v < 0 ) i = -1;
  13235. if( v > 0 ) i = 1;
  13236. }
  13237. if( op == ttEqual )
  13238. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13239. else if( op == ttNotEqual )
  13240. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13241. else if( op == ttLessThan )
  13242. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13243. else if( op == ttLessThanOrEqual )
  13244. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13245. else if( op == ttGreaterThan )
  13246. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13247. else if( op == ttGreaterThanOrEqual )
  13248. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13249. #if AS_SIZEOF_BOOL == 1
  13250. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  13251. #else
  13252. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  13253. #endif
  13254. }
  13255. }
  13256. }
  13257. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  13258. {
  13259. // Put the result on the stack
  13260. if( asReference )
  13261. {
  13262. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  13263. ctx->type.dataType.MakeReference(true);
  13264. }
  13265. else
  13266. {
  13267. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13268. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  13269. else
  13270. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  13271. }
  13272. }
  13273. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  13274. {
  13275. // Both operands must be booleans
  13276. asCDataType to;
  13277. to.SetTokenType(ttBool);
  13278. // Do the actual conversion
  13279. int l = int(reservedVariables.GetLength());
  13280. rctx->bc.GetVarsUsed(reservedVariables);
  13281. lctx->bc.GetVarsUsed(reservedVariables);
  13282. // Allow value types to be converted to bool using 'bool opImplConv()'
  13283. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13284. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13285. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13286. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13287. reservedVariables.SetLength(l);
  13288. // Verify that the conversion was successful
  13289. if( !lctx->type.dataType.IsBooleanType() )
  13290. {
  13291. asCString str;
  13292. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13293. Error(str, node);
  13294. // Force the conversion to allow compilation to proceed
  13295. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13296. }
  13297. if( !rctx->type.dataType.IsBooleanType() )
  13298. {
  13299. asCString str;
  13300. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13301. Error(str, node);
  13302. // Force the conversion to allow compilation to proceed
  13303. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13304. }
  13305. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13306. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13307. // What kind of operator is it?
  13308. if( op == ttUnrecognizedToken )
  13309. op = node->tokenType;
  13310. if( op == ttXor )
  13311. {
  13312. if( !isConstant )
  13313. {
  13314. // Must convert to temporary variable, because we are changing the value before comparison
  13315. ConvertToTempVariableNotIn(lctx, rctx);
  13316. ConvertToTempVariableNotIn(rctx, lctx);
  13317. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13318. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13319. // Make sure they are equal if not false
  13320. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  13321. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  13322. MergeExprBytecode(ctx, lctx);
  13323. MergeExprBytecode(ctx, rctx);
  13324. ProcessDeferredParams(ctx);
  13325. int a = AllocateVariable(ctx->type.dataType, true);
  13326. int b = lctx->type.stackOffset;
  13327. int c = rctx->type.stackOffset;
  13328. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  13329. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13330. }
  13331. else
  13332. {
  13333. // Make sure they are equal if not false
  13334. #if AS_SIZEOF_BOOL == 1
  13335. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13336. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13337. asBYTE v = 0;
  13338. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  13339. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13340. ctx->type.isConstant = true;
  13341. ctx->type.SetConstantB(v);
  13342. #else
  13343. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13344. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13345. asDWORD v = 0;
  13346. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  13347. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13348. ctx->type.isConstant = true;
  13349. ctx->type.SetConstantDW(v);
  13350. #endif
  13351. }
  13352. }
  13353. else if( op == ttAnd ||
  13354. op == ttOr )
  13355. {
  13356. if( !isConstant )
  13357. {
  13358. // If or-operator and first value is 1 the second value shouldn't be calculated
  13359. // if and-operator and first value is 0 the second value shouldn't be calculated
  13360. ConvertToVariable(lctx);
  13361. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13362. MergeExprBytecode(ctx, lctx);
  13363. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  13364. int label1 = nextLabel++;
  13365. int label2 = nextLabel++;
  13366. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  13367. ctx->bc.Instr(asBC_ClrHi);
  13368. if( op == ttAnd )
  13369. {
  13370. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  13371. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  13372. ctx->bc.InstrINT(asBC_JMP, label2);
  13373. }
  13374. else if( op == ttOr )
  13375. {
  13376. ctx->bc.InstrDWORD(asBC_JZ, label1);
  13377. #if AS_SIZEOF_BOOL == 1
  13378. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13379. #else
  13380. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13381. #endif
  13382. ctx->bc.InstrINT(asBC_JMP, label2);
  13383. }
  13384. ctx->bc.Label((short)label1);
  13385. ConvertToVariable(rctx);
  13386. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13387. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  13388. MergeExprBytecode(ctx, rctx);
  13389. ctx->bc.Label((short)label2);
  13390. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  13391. }
  13392. else
  13393. {
  13394. #if AS_SIZEOF_BOOL == 1
  13395. asBYTE v = 0;
  13396. if( op == ttAnd )
  13397. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  13398. else if( op == ttOr )
  13399. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  13400. // Remember the result
  13401. ctx->type.isConstant = true;
  13402. ctx->type.SetConstantB(v);
  13403. #else
  13404. asDWORD v = 0;
  13405. if( op == ttAnd )
  13406. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  13407. else if( op == ttOr )
  13408. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  13409. // Remember the result
  13410. ctx->type.isConstant = true;
  13411. ctx->type.SetConstantDW(v);
  13412. #endif
  13413. }
  13414. }
  13415. }
  13416. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  13417. {
  13418. // Process the property accessor as get
  13419. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  13420. return;
  13421. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  13422. return;
  13423. DetermineSingleFunc(lctx, node);
  13424. DetermineSingleFunc(rctx, node);
  13425. // Make sure lctx doesn't end up with a variable used in rctx
  13426. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  13427. {
  13428. asCArray<int> vars;
  13429. rctx->bc.GetVarsUsed(vars);
  13430. int offset = AllocateVariable(lctx->type.dataType, true);
  13431. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  13432. ReleaseTemporaryVariable(offset, 0);
  13433. }
  13434. if( opToken == ttUnrecognizedToken )
  13435. opToken = node->tokenType;
  13436. // Warn if not both operands are explicit handles or null handles
  13437. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  13438. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  13439. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  13440. {
  13441. Warning(TXT_HANDLE_COMPARISON, node);
  13442. }
  13443. // If one of the operands is a value type used as handle, we should look for the opEquals method
  13444. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  13445. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  13446. (opToken == ttEqual || opToken == ttIs ||
  13447. opToken == ttNotEqual || opToken == ttNotIs) )
  13448. {
  13449. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  13450. // Find the matching opEquals method
  13451. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13452. if( r == 0 )
  13453. {
  13454. // Try again by switching the order of the operands
  13455. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13456. }
  13457. if( r == 1 )
  13458. {
  13459. if( opToken == ttNotEqual || opToken == ttNotIs )
  13460. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  13461. // Success, don't continue
  13462. return;
  13463. }
  13464. else if( r == 0 )
  13465. {
  13466. // Couldn't find opEquals method
  13467. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  13468. }
  13469. // Compiler error, don't continue
  13470. #if AS_SIZEOF_BOOL == 1
  13471. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13472. #else
  13473. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13474. #endif
  13475. return;
  13476. }
  13477. // Implicitly convert null to the other type
  13478. asCDataType to;
  13479. if( lctx->type.IsNullConstant() )
  13480. to = rctx->type.dataType;
  13481. else if( rctx->type.IsNullConstant() )
  13482. to = lctx->type.dataType;
  13483. else
  13484. {
  13485. // Find a common base type
  13486. asCExprContext tmp(engine);
  13487. tmp.type = rctx->type;
  13488. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  13489. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  13490. to = lctx->type.dataType;
  13491. else
  13492. to = rctx->type.dataType;
  13493. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  13494. to.MakeHandleToConst(true);
  13495. }
  13496. // Need to pop the value if it is a null constant
  13497. if( lctx->type.IsNullConstant() )
  13498. lctx->bc.Instr(asBC_PopPtr);
  13499. if( rctx->type.IsNullConstant() )
  13500. rctx->bc.Instr(asBC_PopPtr);
  13501. // Convert both sides to explicit handles
  13502. to.MakeHandle(true);
  13503. to.MakeReference(false);
  13504. if( !to.IsObjectHandle() )
  13505. {
  13506. // Compiler error, don't continue
  13507. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13508. #if AS_SIZEOF_BOOL == 1
  13509. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13510. #else
  13511. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13512. #endif
  13513. return;
  13514. }
  13515. // Do the conversion
  13516. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13517. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13518. // Both operands must be of the same type
  13519. // Verify that the conversion was successful
  13520. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13521. {
  13522. asCString str;
  13523. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13524. Error(str, node);
  13525. }
  13526. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13527. {
  13528. asCString str;
  13529. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13530. Error(str, node);
  13531. }
  13532. // Make sure it really is handles that are being compared
  13533. if( !lctx->type.dataType.IsObjectHandle() )
  13534. {
  13535. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13536. }
  13537. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13538. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  13539. {
  13540. // Make sure handles received as parameters by reference are copied to a local variable before the
  13541. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  13542. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  13543. lctx->type.isVariable = false;
  13544. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  13545. rctx->type.isVariable = false;
  13546. // TODO: runtime optimize: don't do REFCPY if not necessary
  13547. ConvertToVariableNotIn(lctx, rctx);
  13548. ConvertToVariable(rctx);
  13549. // Pop the pointers from the stack as they will not be used
  13550. lctx->bc.Instr(asBC_PopPtr);
  13551. rctx->bc.Instr(asBC_PopPtr);
  13552. MergeExprBytecode(ctx, lctx);
  13553. MergeExprBytecode(ctx, rctx);
  13554. int a = AllocateVariable(ctx->type.dataType, true);
  13555. int b = lctx->type.stackOffset;
  13556. int c = rctx->type.stackOffset;
  13557. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  13558. if( opToken == ttEqual || opToken == ttIs )
  13559. ctx->bc.Instr(asBC_TZ);
  13560. else if( opToken == ttNotEqual || opToken == ttNotIs )
  13561. ctx->bc.Instr(asBC_TNZ);
  13562. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13563. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13564. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  13565. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  13566. ProcessDeferredParams(ctx);
  13567. }
  13568. else
  13569. {
  13570. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13571. Error(TXT_ILLEGAL_OPERATION, node);
  13572. }
  13573. }
  13574. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  13575. {
  13576. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  13577. // A shared object may not call non-shared functions
  13578. if( outFunc->IsShared() && !descr->IsShared() )
  13579. {
  13580. asCString msg;
  13581. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  13582. Error(msg, ctx->exprNode);
  13583. }
  13584. // Check if the function is private or protected
  13585. if (descr->IsPrivate())
  13586. {
  13587. asCObjectType *type = descr->objectType;
  13588. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13589. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13590. asASSERT(type);
  13591. if( (type != outFunc->GetObjectType()) )
  13592. {
  13593. asCString msg;
  13594. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13595. Error(msg, ctx->exprNode);
  13596. }
  13597. }
  13598. else if (descr->IsProtected())
  13599. {
  13600. asCObjectType *type = descr->objectType;
  13601. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13602. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13603. asASSERT(type);
  13604. if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type))))
  13605. {
  13606. asCString msg;
  13607. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13608. Error(msg, ctx->exprNode);
  13609. }
  13610. }
  13611. int argSize = descr->GetSpaceNeededForArguments();
  13612. // If we're calling a class method we must make sure the object is guaranteed to stay
  13613. // alive throughout the call by holding on to a reference in a local variable. This must
  13614. // be done for any methods that return references, and any calls on script objects.
  13615. // Application registered objects are assumed to know to keep themselves alive even
  13616. // if the method doesn't return a reference.
  13617. if( !ctx->type.isRefSafe &&
  13618. descr->objectType &&
  13619. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  13620. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  13621. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  13622. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  13623. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  13624. {
  13625. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  13626. // local variable and then refer to the same for each call. An alias for the global variable
  13627. // should be stored in the variable scope so that the compiler can find it. For loops and
  13628. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  13629. // higher scope to increase the probability of re-use.
  13630. int tempRef = AllocateVariable(ctx->type.dataType, true);
  13631. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  13632. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  13633. // Add the release of this reference as a deferred expression
  13634. asSDeferredParam deferred;
  13635. deferred.origExpr = 0;
  13636. deferred.argInOutFlags = asTM_INREF;
  13637. deferred.argNode = 0;
  13638. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  13639. ctx->deferredParams.PushLast(deferred);
  13640. // Forget the current type
  13641. ctx->type.SetDummy();
  13642. }
  13643. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  13644. if( descr->DoesReturnOnStack() && !useVariable )
  13645. {
  13646. useVariable = true;
  13647. varOffset = AllocateVariable(descr->returnType, true);
  13648. // Push the pointer to the pre-allocated space for the return value
  13649. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  13650. if( descr->objectType )
  13651. {
  13652. // The object pointer is already on the stack, but should be the top
  13653. // one, so we need to swap the pointers in order to get the correct
  13654. ctx->bc.Instr(asBC_SwapPtr);
  13655. }
  13656. }
  13657. if( isConstructor )
  13658. {
  13659. // Sometimes the value types are allocated on the heap,
  13660. // which is when this way of constructing them is used.
  13661. asASSERT(useVariable == false);
  13662. if( (objType->flags & asOBJ_TEMPLATE) )
  13663. {
  13664. asASSERT( descr->funcType == asFUNC_SCRIPT );
  13665. // Find the id of the real constructor and not the generated stub
  13666. asUINT id = 0;
  13667. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  13668. while( bc )
  13669. {
  13670. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  13671. {
  13672. id = asBC_INTARG(bc);
  13673. break;
  13674. }
  13675. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  13676. }
  13677. asASSERT( id );
  13678. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  13679. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  13680. }
  13681. else
  13682. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  13683. // The instruction has already moved the returned object to the variable
  13684. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  13685. ctx->type.isLValue = false;
  13686. // Clean up arguments
  13687. if( args )
  13688. AfterFunctionCall(funcId, *args, ctx, false);
  13689. ProcessDeferredParams(ctx);
  13690. return;
  13691. }
  13692. else
  13693. {
  13694. if( descr->objectType )
  13695. argSize += AS_PTR_SIZE;
  13696. // If the function returns an object by value the address of the location
  13697. // where the value should be stored is passed as an argument too
  13698. if( descr->DoesReturnOnStack() )
  13699. argSize += AS_PTR_SIZE;
  13700. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  13701. // should be made with asBC_CALL as it is faster. Examples where this
  13702. // is known is for example finalled methods where the class doesn't derive
  13703. // from any other, or even non-finalled methods but where it is known
  13704. // at compile time the true type of the object. The first should be
  13705. // quite easy to determine, but the latter will be quite complex and possibly
  13706. // not worth it.
  13707. if( descr->funcType == asFUNC_IMPORTED )
  13708. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  13709. // TODO: Maybe we need two different byte codes
  13710. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  13711. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  13712. else if( descr->funcType == asFUNC_SCRIPT )
  13713. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  13714. else if( descr->funcType == asFUNC_SYSTEM )
  13715. {
  13716. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  13717. // type &obj::func(int)
  13718. // type &obj::func(uint)
  13719. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  13720. descr->parameterTypes.GetLength() == 1 &&
  13721. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  13722. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  13723. !descr->parameterTypes[0].IsReference() )
  13724. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  13725. else
  13726. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  13727. }
  13728. else if( descr->funcType == asFUNC_FUNCDEF )
  13729. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  13730. }
  13731. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  13732. {
  13733. int returnOffset = 0;
  13734. asCExprValue tmpExpr = ctx->type;
  13735. if( descr->DoesReturnOnStack() )
  13736. {
  13737. asASSERT( useVariable );
  13738. // The variable was allocated before the function was called
  13739. returnOffset = varOffset;
  13740. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13741. // The variable was initialized by the function, so we need to mark it as initialized here
  13742. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  13743. }
  13744. else
  13745. {
  13746. if( useVariable )
  13747. {
  13748. // Use the given variable
  13749. returnOffset = varOffset;
  13750. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  13751. }
  13752. else
  13753. {
  13754. // Allocate a temporary variable for the returned object
  13755. // The returned object will actually be allocated on the heap, so
  13756. // we must force the allocation of the variable to do the same
  13757. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  13758. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13759. }
  13760. // Move the pointer from the object register to the temporary variable
  13761. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  13762. }
  13763. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13764. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  13765. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  13766. // Clean up arguments
  13767. if( args )
  13768. AfterFunctionCall(funcId, *args, ctx, false);
  13769. ProcessDeferredParams(ctx);
  13770. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  13771. }
  13772. else if( descr->returnType.IsReference() )
  13773. {
  13774. asASSERT(useVariable == false);
  13775. // We cannot clean up the arguments yet, because the
  13776. // reference might be pointing to one of them.
  13777. if( args )
  13778. AfterFunctionCall(funcId, *args, ctx, true);
  13779. // Do not process the output parameters yet, because it
  13780. // might invalidate the returned reference
  13781. // If the context holds a variable that needs cleanup
  13782. // store it as a deferred parameter so it will be cleaned up
  13783. // afterwards.
  13784. if( ctx->type.isTemporary )
  13785. {
  13786. asSDeferredParam defer;
  13787. defer.argNode = 0;
  13788. defer.argType = ctx->type;
  13789. defer.argInOutFlags = asTM_INOUTREF;
  13790. defer.origExpr = 0;
  13791. ctx->deferredParams.PushLast(defer);
  13792. }
  13793. ctx->type.Set(descr->returnType);
  13794. if( !descr->returnType.IsPrimitive() )
  13795. {
  13796. ctx->bc.Instr(asBC_PshRPtr);
  13797. if( descr->returnType.IsObject() &&
  13798. !descr->returnType.IsObjectHandle() )
  13799. {
  13800. // We are getting the pointer to the object
  13801. // not a pointer to a object variable
  13802. ctx->type.dataType.MakeReference(false);
  13803. }
  13804. }
  13805. // A returned reference can be used as lvalue
  13806. ctx->type.isLValue = true;
  13807. }
  13808. else
  13809. {
  13810. asCExprValue tmpExpr = ctx->type;
  13811. if( descr->returnType.GetSizeInMemoryBytes() )
  13812. {
  13813. int offset;
  13814. if (useVariable)
  13815. offset = varOffset;
  13816. else
  13817. {
  13818. // Allocate a temporary variable to hold the value, but make sure
  13819. // the temporary variable isn't used in any of the deferred arguments
  13820. int l = int(reservedVariables.GetLength());
  13821. for (asUINT n = 0; args && n < args->GetLength(); n++)
  13822. {
  13823. asCExprContext *expr = (*args)[n]->origExpr;
  13824. if (expr)
  13825. expr->bc.GetVarsUsed(reservedVariables);
  13826. }
  13827. offset = AllocateVariable(descr->returnType, true);
  13828. reservedVariables.SetLength(l);
  13829. }
  13830. ctx->type.SetVariable(descr->returnType, offset, true);
  13831. // Move the value from the return register to the variable
  13832. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  13833. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  13834. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  13835. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  13836. }
  13837. else
  13838. ctx->type.Set(descr->returnType);
  13839. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13840. ctx->type.isLValue = false;
  13841. // Clean up arguments
  13842. if( args )
  13843. AfterFunctionCall(funcId, *args, ctx, false);
  13844. ProcessDeferredParams(ctx);
  13845. }
  13846. }
  13847. // This only merges the bytecode, but doesn't modify the type of the final context
  13848. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  13849. {
  13850. before->bc.AddCode(&after->bc);
  13851. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  13852. {
  13853. before->deferredParams.PushLast(after->deferredParams[n]);
  13854. after->deferredParams[n].origExpr = 0;
  13855. }
  13856. after->deferredParams.SetLength(0);
  13857. }
  13858. // This merges both bytecode and the type of the final context
  13859. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  13860. {
  13861. MergeExprBytecode(before, after);
  13862. before->Merge(after);
  13863. }
  13864. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  13865. {
  13866. if( funcs.GetLength() == 0 ) return;
  13867. // This is only done for object methods
  13868. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  13869. if( !desc || desc->objectType == 0 ) return;
  13870. // Check if there are any non-const matches
  13871. asUINT n;
  13872. bool foundNonConst = false;
  13873. for( n = 0; n < funcs.GetLength(); n++ )
  13874. {
  13875. desc = builder->GetFunctionDescription(funcs[n]);
  13876. if( desc && desc->IsReadOnly() != removeConst )
  13877. {
  13878. foundNonConst = true;
  13879. break;
  13880. }
  13881. }
  13882. if( foundNonConst )
  13883. {
  13884. // Remove all const methods
  13885. for( n = 0; n < funcs.GetLength(); n++ )
  13886. {
  13887. desc = builder->GetFunctionDescription(funcs[n]);
  13888. if( desc && desc->IsReadOnly() == removeConst )
  13889. {
  13890. if( n == funcs.GetLength() - 1 )
  13891. funcs.PopLast();
  13892. else
  13893. funcs[n] = funcs.PopLast();
  13894. n--;
  13895. }
  13896. }
  13897. }
  13898. }
  13899. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13900. asCExprValue::asCExprValue()
  13901. {
  13902. isTemporary = false;
  13903. stackOffset = 0;
  13904. isConstant = false;
  13905. isVariable = false;
  13906. isExplicitHandle = false;
  13907. qwordValue = 0;
  13908. isLValue = false;
  13909. isRefToLocal = false;
  13910. isRefSafe = false;
  13911. }
  13912. void asCExprValue::Set(const asCDataType &dt)
  13913. {
  13914. dataType = dt;
  13915. isTemporary = false;
  13916. stackOffset = 0;
  13917. isConstant = false;
  13918. isVariable = false;
  13919. isExplicitHandle = false;
  13920. qwordValue = 0;
  13921. isLValue = false;
  13922. isRefToLocal = false;
  13923. isRefSafe = false;
  13924. }
  13925. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  13926. {
  13927. Set(in_dt);
  13928. this->isVariable = true;
  13929. this->isTemporary = in_isTemporary;
  13930. this->stackOffset = (short)in_stackOffset;
  13931. }
  13932. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  13933. {
  13934. Set(dt);
  13935. isConstant = true;
  13936. SetConstantQW(value);
  13937. }
  13938. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  13939. {
  13940. Set(dt);
  13941. isConstant = true;
  13942. SetConstantDW(value);
  13943. }
  13944. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  13945. {
  13946. Set(dt);
  13947. isConstant = true;
  13948. SetConstantB(value);
  13949. }
  13950. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  13951. {
  13952. Set(dt);
  13953. isConstant = true;
  13954. SetConstantW(value);
  13955. }
  13956. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  13957. {
  13958. Set(dt);
  13959. isConstant = true;
  13960. SetConstantF(value);
  13961. }
  13962. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  13963. {
  13964. Set(dt);
  13965. isConstant = true;
  13966. SetConstantD(value);
  13967. }
  13968. void asCExprValue::SetConstantQW(asQWORD value)
  13969. {
  13970. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13971. qwordValue = value;
  13972. }
  13973. void asCExprValue::SetConstantDW(asDWORD value)
  13974. {
  13975. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13976. dwordValue = value;
  13977. }
  13978. void asCExprValue::SetConstantW(asWORD value)
  13979. {
  13980. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13981. wordValue = value;
  13982. }
  13983. void asCExprValue::SetConstantB(asBYTE value)
  13984. {
  13985. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  13986. byteValue = value;
  13987. }
  13988. void asCExprValue::SetConstantF(float value)
  13989. {
  13990. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13991. floatValue = value;
  13992. }
  13993. void asCExprValue::SetConstantD(double value)
  13994. {
  13995. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13996. doubleValue = value;
  13997. }
  13998. asQWORD asCExprValue::GetConstantQW()
  13999. {
  14000. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14001. return qwordValue;
  14002. }
  14003. asDWORD asCExprValue::GetConstantDW()
  14004. {
  14005. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14006. return dwordValue;
  14007. }
  14008. asWORD asCExprValue::GetConstantW()
  14009. {
  14010. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  14011. return wordValue;
  14012. }
  14013. asBYTE asCExprValue::GetConstantB()
  14014. {
  14015. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  14016. return byteValue;
  14017. }
  14018. float asCExprValue::GetConstantF()
  14019. {
  14020. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14021. return floatValue;
  14022. }
  14023. double asCExprValue::GetConstantD()
  14024. {
  14025. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14026. return doubleValue;
  14027. }
  14028. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  14029. {
  14030. Set(dt);
  14031. isConstant = true;
  14032. // This code is necessary to guarantee that the code
  14033. // works on both big endian and little endian CPUs.
  14034. if (dataType.GetSizeInMemoryBytes() == 1)
  14035. byteValue = (asBYTE)qw;
  14036. if (dataType.GetSizeInMemoryBytes() == 2)
  14037. wordValue = (asWORD)qw;
  14038. if (dataType.GetSizeInMemoryBytes() == 4)
  14039. dwordValue = (asDWORD)qw;
  14040. else
  14041. qwordValue = qw;
  14042. }
  14043. asQWORD asCExprValue::GetConstantData()
  14044. {
  14045. asQWORD qw = 0;
  14046. // This code is necessary to guarantee that the code
  14047. // works on both big endian and little endian CPUs.
  14048. if (dataType.GetSizeInMemoryBytes() == 1)
  14049. qw = byteValue;
  14050. if (dataType.GetSizeInMemoryBytes() == 2)
  14051. qw = wordValue;
  14052. if (dataType.GetSizeInMemoryBytes() == 4)
  14053. qw = dwordValue;
  14054. else
  14055. qw = qwordValue;
  14056. return qw;
  14057. }
  14058. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  14059. {
  14060. // This is used for when the expression evaluates to a
  14061. // function, but it is not yet known exactly which. The
  14062. // owner expression will hold the name of the function
  14063. // to determine the exact function when the signature is
  14064. // known.
  14065. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  14066. isConstant = true;
  14067. isExplicitHandle = false;
  14068. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  14069. isLValue = false;
  14070. }
  14071. bool asCExprValue::IsUndefinedFuncHandle() const
  14072. {
  14073. if (isConstant == false) return false;
  14074. if (qwordValue == 0) return false;
  14075. if (isLValue) return false;
  14076. if (dataType.GetTypeInfo() == 0) return false;
  14077. if (dataType.GetTypeInfo()->name != "$func") return false;
  14078. if (dataType.IsFuncdef()) return false;
  14079. return true;
  14080. }
  14081. void asCExprValue::SetNullConstant()
  14082. {
  14083. Set(asCDataType::CreateNullHandle());
  14084. isConstant = true;
  14085. isExplicitHandle = false;
  14086. qwordValue = 0;
  14087. isLValue = false;
  14088. }
  14089. bool asCExprValue::IsNullConstant() const
  14090. {
  14091. // We can't check the actual object type, because the null constant may have been cast to another type
  14092. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  14093. return true;
  14094. return false;
  14095. }
  14096. void asCExprValue::SetVoid()
  14097. {
  14098. Set(asCDataType::CreatePrimitive(ttVoid, false));
  14099. isLValue = false;
  14100. isConstant = true;
  14101. }
  14102. bool asCExprValue::IsVoid() const
  14103. {
  14104. if (dataType.GetTokenType() == ttVoid)
  14105. return true;
  14106. return false;
  14107. }
  14108. void asCExprValue::SetDummy()
  14109. {
  14110. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  14111. }
  14112. ////////////////////////////////////////////////////////////////////////////////////////////////
  14113. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  14114. {
  14115. property_arg = 0;
  14116. Clear();
  14117. }
  14118. asCExprContext::~asCExprContext()
  14119. {
  14120. if (property_arg)
  14121. asDELETE(property_arg, asCExprContext);
  14122. }
  14123. void asCExprContext::Clear()
  14124. {
  14125. bc.ClearAll();
  14126. type.Set(asCDataType());
  14127. deferredParams.SetLength(0);
  14128. if (property_arg)
  14129. asDELETE(property_arg, asCExprContext);
  14130. property_arg = 0;
  14131. exprNode = 0;
  14132. origExpr = 0;
  14133. property_get = 0;
  14134. property_set = 0;
  14135. property_const = false;
  14136. property_handle = false;
  14137. property_ref = false;
  14138. methodName = "";
  14139. enumValue = "";
  14140. symbolNamespace = 0;
  14141. isVoidExpression = false;
  14142. isCleanArg = false;
  14143. isAnonymousInitList = false;
  14144. origCode = 0;
  14145. }
  14146. bool asCExprContext::IsClassMethod() const
  14147. {
  14148. if (type.dataType.GetTypeInfo() == 0) return false;
  14149. if (methodName == "") return false;
  14150. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14151. if (isAnonymousInitList) return false;
  14152. return true;
  14153. }
  14154. bool asCExprContext::IsGlobalFunc() const
  14155. {
  14156. if (type.dataType.GetTypeInfo() == 0) return false;
  14157. if (methodName == "") return false;
  14158. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14159. if (isAnonymousInitList) return false;
  14160. return true;
  14161. }
  14162. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  14163. {
  14164. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  14165. asASSERT(bc.GetLastInstr() == -1);
  14166. Clear();
  14167. type.SetUndefinedFuncHandle(bc.GetEngine());
  14168. exprNode = funcDecl;
  14169. }
  14170. bool asCExprContext::IsLambda() const
  14171. {
  14172. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  14173. return true;
  14174. return false;
  14175. }
  14176. void asCExprContext::SetVoidExpression()
  14177. {
  14178. Clear();
  14179. type.SetVoid();
  14180. isVoidExpression = true;
  14181. }
  14182. bool asCExprContext::IsVoidExpression() const
  14183. {
  14184. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  14185. return true;
  14186. return false;
  14187. }
  14188. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script)
  14189. {
  14190. Clear();
  14191. exprNode = initList;
  14192. origCode = script;
  14193. isAnonymousInitList = true;
  14194. }
  14195. bool asCExprContext::IsAnonymousInitList() const
  14196. {
  14197. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  14198. return true;
  14199. return false;
  14200. }
  14201. void asCExprContext::Copy(asCExprContext *other)
  14202. {
  14203. type = other->type;
  14204. property_get = other->property_get;
  14205. property_set = other->property_set;
  14206. property_const = other->property_const;
  14207. property_handle = other->property_handle;
  14208. property_ref = other->property_ref;
  14209. property_arg = other->property_arg;
  14210. exprNode = other->exprNode;
  14211. methodName = other->methodName;
  14212. enumValue = other->enumValue;
  14213. isVoidExpression = other->isVoidExpression;
  14214. isCleanArg = other->isCleanArg;
  14215. isAnonymousInitList = other->isAnonymousInitList;
  14216. origCode = other->origCode;
  14217. // Do not copy the origExpr member
  14218. }
  14219. void asCExprContext::Merge(asCExprContext *after)
  14220. {
  14221. // Overwrite properties with the expression that comes after
  14222. Copy(after);
  14223. // Clean the properties in 'after' that have now moved into
  14224. // this structure so they are not cleaned up accidentally
  14225. after->property_arg = 0;
  14226. }
  14227. END_AS_NAMESPACE
  14228. #endif // AS_NO_COMPILER