as_compiler.cpp 524 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2022 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() pow()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. #include "as_context.h" // as_powi()
  40. BEGIN_AS_NAMESPACE
  41. //
  42. // The calling convention rules for script functions:
  43. // - 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
  44. // - 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
  45. // - The object pointer is always passed as the first argument, position 0
  46. // - 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
  47. //
  48. // TODO: I must correct the interpretation of a reference to objects in the compiler.
  49. // A reference should mean that a pointer to the object is on the stack.
  50. // No expression should end up as non-references to objects, as the actual object is
  51. // never put on the stack.
  52. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  53. // Function parameters of called functions can also be non-references, but in that case it means the
  54. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  55. //
  56. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  57. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  58. // is currently stored, i.e. in variable, in register, on stack, etc.
  59. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  60. {
  61. builder = 0;
  62. script = 0;
  63. variables = 0;
  64. isProcessingDeferredParams = false;
  65. isCompilingDefaultArg = false;
  66. noCodeOutput = 0;
  67. }
  68. asCCompiler::~asCCompiler()
  69. {
  70. while( variables )
  71. {
  72. asCVariableScope *var = variables;
  73. variables = variables->parent;
  74. asDELETE(var,asCVariableScope);
  75. }
  76. // Clean up all the string constants that were allocated. By now the script
  77. // functions that were compiled successfully already holds their own references
  78. for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
  79. engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
  80. usedStringConstants.SetLength(0);
  81. // Clean up the temporary script nodes that were allocated during compilation
  82. for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++)
  83. nodesToFreeUponComplete[n]->Destroy(engine);
  84. }
  85. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  86. {
  87. this->builder = in_builder;
  88. this->engine = in_builder->engine;
  89. this->script = in_script;
  90. this->outFunc = in_outFunc;
  91. hasCompileErrors = false;
  92. m_isConstructor = false;
  93. m_isConstructorCalled = false;
  94. m_classDecl = 0;
  95. m_globalVar = 0;
  96. nextLabel = 0;
  97. breakLabels.SetLength(0);
  98. continueLabels.SetLength(0);
  99. numLambdas = 0;
  100. byteCode.ClearAll();
  101. }
  102. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  103. {
  104. Reset(in_builder, in_script, in_outFunc);
  105. m_classDecl = in_classDecl;
  106. // Insert a JitEntry at the start of the function for JIT compilers
  107. byteCode.InstrPTR(asBC_JitEntry, 0);
  108. // Add a variable scope that might be needed to declare dummy variables
  109. // in case the member initialization refers to undefined symbols.
  110. AddVariableScope();
  111. // Initialize the class members that have no explicit expression first. This will allow the
  112. // base class' constructor to access these members without worry they will be uninitialized.
  113. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  114. CompileMemberInitialization(&byteCode, true);
  115. // If the class is derived from another, then the base class' default constructor must be called
  116. if( outFunc->objectType->derivedFrom )
  117. {
  118. // Make sure the base class really has a default constructor
  119. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  120. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  121. // Call the base class' default constructor
  122. byteCode.InstrSHORT(asBC_PSF, 0);
  123. byteCode.Instr(asBC_RDSPtr);
  124. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  125. }
  126. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  127. // to access the base class members without worry they will be uninitialized
  128. CompileMemberInitialization(&byteCode, false);
  129. byteCode.OptimizeLocally(tempVariableOffsets);
  130. // If there are compile errors, there is no reason to build the final code
  131. if( hasCompileErrors )
  132. return -1;
  133. // Pop the object pointer from the stack
  134. byteCode.Ret(AS_PTR_SIZE);
  135. // Count total variable size
  136. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  137. outFunc->scriptData->variableSpace = varSize;
  138. FinalizeFunction();
  139. #ifdef AS_DEBUG
  140. // DEBUG: output byte code
  141. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  142. #endif
  143. return 0;
  144. }
  145. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  146. {
  147. Reset(in_builder, in_script, in_outFunc);
  148. // Insert a JitEntry at the start of the function for JIT compilers
  149. byteCode.InstrPTR(asBC_JitEntry, 0);
  150. // Find the corresponding constructor
  151. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  152. int constructor = 0;
  153. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  154. {
  155. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  156. {
  157. constructor = dt.GetBehaviour()->constructors[n];
  158. break;
  159. }
  160. }
  161. // Allocate the class and instantiate it with the constructor
  162. int varOffset = AllocateVariable(dt, true);
  163. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  164. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  165. // Copy all arguments to the top of the stack
  166. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  167. int offset = (int)outFunc->GetSpaceNeededForArguments();
  168. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  169. {
  170. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  171. outFunc->parameterTypes[a].IsReference() )
  172. {
  173. offset -= AS_PTR_SIZE;
  174. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  175. }
  176. else
  177. {
  178. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  179. {
  180. offset -= 2;
  181. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  182. }
  183. else
  184. {
  185. offset -= 1;
  186. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  187. }
  188. }
  189. }
  190. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  191. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  192. // Return a handle to the newly created object
  193. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  194. byteCode.Ret(argDwords);
  195. FinalizeFunction();
  196. // Tell the virtual machine not to clean up parameters on exception
  197. outFunc->dontCleanUpOnException = true;
  198. /*
  199. #ifdef AS_DEBUG
  200. // DEBUG: output byte code
  201. asCString args;
  202. args.Format("%d", outFunc->parameterTypes.GetLength());
  203. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  204. #endif
  205. */
  206. return 0;
  207. }
  208. void asCCompiler::FinalizeFunction()
  209. {
  210. TimeIt("asCCompiler::FinalizeFunction");
  211. asASSERT( outFunc->scriptData );
  212. asUINT n;
  213. // Add the type of all temporary variables to the function so this is known to debugger and serializer
  214. for (n = 0; n < tempVariableOffsets.GetLength(); n++)
  215. {
  216. int slot = GetVariableSlot(tempVariableOffsets[n]);
  217. outFunc->AddVariable("", variableAllocations[slot], tempVariableOffsets[n], variableIsOnHeap[slot]);
  218. }
  219. // Add the type of unnamed parameters
  220. int stackPos = outFunc->objectType ? -AS_PTR_SIZE : 0;
  221. // If the return type is a value type returned by value the address of the
  222. // location where the value will be stored is pushed on the stack before
  223. // the arguments
  224. bool isDestructor = (outFunc->name.GetLength() > 0 && outFunc->name[0] == '~') ? true : false;
  225. if (!(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack())
  226. stackPos -= AS_PTR_SIZE;
  227. for (n = 0; n < outFunc->parameterNames.GetLength(); n++)
  228. {
  229. // Get the parameter type
  230. asCDataType& type = outFunc->parameterTypes[n];
  231. // If the parameter has a name then it was already added to the list in SetupParametersAndReturnVariable
  232. if (outFunc->parameterNames[n] == "")
  233. {
  234. // Object types passed by value are considered to be on heap
  235. bool onHeap = !type.IsReference() && type.IsObject() && !type.IsObjectHandle();
  236. outFunc->AddVariable("", type, stackPos, onHeap);
  237. }
  238. // Move to next parameter
  239. stackPos -= type.GetSizeOnStackDWords();
  240. }
  241. // Add the return type too at the end if it returns on the stack, which is when it uses a hidden parameter
  242. if (outFunc->DoesReturnOnStack())
  243. {
  244. // Though declared as return by value, locally the return value is seen as a reference
  245. asCDataType returnType = outFunc->returnType;
  246. returnType.MakeReference(true);
  247. outFunc->AddVariable("", returnType, outFunc->objectType ? -AS_PTR_SIZE : 0, false);
  248. }
  249. // Finalize the bytecode
  250. byteCode.Finalize(tempVariableOffsets);
  251. // extract the try/catch info before object variable info, as
  252. // some variable info is not needed if there are no try/catch blocks
  253. byteCode.ExtractTryCatchInfo(outFunc);
  254. byteCode.ExtractObjectVariableInfo(outFunc);
  255. // Copy byte code to the function
  256. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  257. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  258. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  259. outFunc->AddReferences();
  260. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  261. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  262. // Extract the script section indexes too if there are any entries that are different from the function's script section
  263. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  264. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  265. {
  266. if( byteCode.sectionIdxs[n] != lastIdx )
  267. {
  268. lastIdx = byteCode.sectionIdxs[n];
  269. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  270. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  271. }
  272. }
  273. }
  274. // internal
  275. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  276. {
  277. int stackPos = 0;
  278. if( outFunc->objectType )
  279. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  280. // Add the first variable scope, which the parameters and
  281. // variables declared in the outermost statement block is
  282. // part of.
  283. AddVariableScope();
  284. bool isDestructor = false;
  285. asCDataType returnType;
  286. // Examine return type
  287. returnType = outFunc->returnType;
  288. // Check if this is a constructor or destructor
  289. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  290. {
  291. if( outFunc->name[0] == '~' )
  292. isDestructor = true;
  293. else if( outFunc->objectType->name == outFunc->name )
  294. m_isConstructor = true;
  295. }
  296. // Is the return type allowed?
  297. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  298. !returnType.CanBeInstantiated() &&
  299. !returnType.IsReference() &&
  300. !returnType.IsObjectHandle() )
  301. {
  302. // TODO: Hasn't this been validated by the builder already?
  303. asCString str;
  304. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  305. Error(str, func);
  306. }
  307. // If the return type is a value type returned by value the address of the
  308. // location where the value will be stored is pushed on the stack before
  309. // the arguments
  310. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  311. stackPos -= AS_PTR_SIZE;
  312. asCVariableScope vs(0);
  313. // Declare parameters
  314. asUINT n;
  315. for( n = 0; n < parameterNames.GetLength(); n++ )
  316. {
  317. // Get the parameter type
  318. asCDataType &type = outFunc->parameterTypes[n];
  319. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  320. // Is the data type allowed?
  321. // TODO: Hasn't this been validated by the builder already?
  322. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  323. (!type.IsReference() && !type.CanBeInstantiated()) )
  324. {
  325. asCString parm = type.Format(outFunc->nameSpace);
  326. if( inoutFlag == asTM_INREF )
  327. parm += "in";
  328. else if( inoutFlag == asTM_OUTREF )
  329. parm += "out";
  330. asCString str;
  331. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  332. Error(str, func);
  333. }
  334. // If the parameter has a name then declare it as variable
  335. // Object types passed by value are considered to be on heap
  336. bool onHeap = !type.IsReference() && type.IsObject() && !type.IsObjectHandle();
  337. if( parameterNames[n] != "" )
  338. {
  339. asCString &name = parameterNames[n];
  340. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, onHeap) < 0 )
  341. {
  342. // TODO: It might be an out-of-memory too
  343. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  344. }
  345. // Add marker for variable declaration
  346. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  347. outFunc->AddVariable(name, type, stackPos, onHeap);
  348. }
  349. else
  350. vs.DeclareVariable("", type, stackPos, onHeap);
  351. // Move to next parameter
  352. stackPos -= type.GetSizeOnStackDWords();
  353. }
  354. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  355. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  356. variables->DeclareVariable("return", returnType, stackPos, false);
  357. return stackPos;
  358. }
  359. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  360. {
  361. asASSERT( m_classDecl );
  362. // Initialize each member in the order they were declared
  363. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  364. {
  365. asCObjectProperty *prop = outFunc->objectType->properties[n];
  366. // Check if the property has an initialization expression
  367. asCParser parser(builder);
  368. asCScriptNode *declNode = 0;
  369. asCScriptNode *initNode = 0;
  370. asCScriptCode *initScript = 0;
  371. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  372. {
  373. if( m_classDecl->propInits[m].name == prop->name )
  374. {
  375. declNode = m_classDecl->propInits[m].declNode;
  376. initNode = m_classDecl->propInits[m].initNode;
  377. initScript = m_classDecl->propInits[m].file;
  378. break;
  379. }
  380. }
  381. // If declNode is null, the property was inherited in which case
  382. // it was already initialized by the base class' constructor
  383. if( declNode )
  384. {
  385. if( initNode )
  386. {
  387. if( onlyDefaults )
  388. continue;
  389. #ifdef AS_NO_MEMBER_INIT
  390. // Give an error as the initialization in the declaration has been disabled
  391. asCScriptCode *origScript = script;
  392. script = initScript;
  393. Error("Initialization of members in declaration is not supported", initNode);
  394. script = origScript;
  395. // Clear the initialization node
  396. initNode = 0;
  397. initScript = script;
  398. #else
  399. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  400. int r = parser.ParseVarInit(initScript, initNode);
  401. if( r < 0 )
  402. continue;
  403. initNode = parser.GetScriptNode();
  404. #endif
  405. }
  406. else
  407. {
  408. if( !onlyDefaults )
  409. continue;
  410. }
  411. #ifdef AS_NO_MEMBER_INIT
  412. // The initialization will be done in the asCScriptObject constructor, so
  413. // here we should just validate that the member has a default constructor
  414. if( prop->type.IsObject() &&
  415. !prop->type.IsObjectHandle() &&
  416. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  417. prop->type.GetBehaviour()->factory == 0) ||
  418. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  419. prop->type.GetBehaviour()->construct == 0 &&
  420. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  421. {
  422. // Class has no default factory/constructor.
  423. asCString str;
  424. // TODO: funcdef: asCDataType should have a GetTypeName()
  425. if( prop->type.GetFuncDef() )
  426. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  427. else
  428. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  429. Error(str, declNode);
  430. }
  431. #else
  432. // Temporarily set the script that is being compiled to where the member initialization is declared.
  433. // The script can be different when including mixin classes from a different script section
  434. asCScriptCode *origScript = script;
  435. script = initScript;
  436. // Add a line instruction with the position of the declaration
  437. LineInstr(bc, declNode->tokenPos);
  438. // Compile the initialization
  439. asQWORD constantValue;
  440. asCByteCode bcInit(engine);
  441. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  442. bcInit.OptimizeLocally(tempVariableOffsets);
  443. bc->AddCode(&bcInit);
  444. script = origScript;
  445. #endif
  446. }
  447. }
  448. }
  449. // Entry
  450. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  451. {
  452. TimeIt("asCCompiler::CompileFunction");
  453. Reset(in_builder, in_script, in_outFunc);
  454. int buildErrors = builder->numErrors;
  455. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  456. //--------------------------------------------
  457. // Compile the statement block
  458. if( m_isConstructor )
  459. m_classDecl = in_classDecl;
  460. // We need to parse the statement block now
  461. asCScriptNode *blockBegin;
  462. // If the function signature was implicit, e.g. virtual property accessor or
  463. // lambda function, then the received node already is the statement block
  464. if( in_func->nodeType != snStatementBlock )
  465. blockBegin = in_func->lastChild;
  466. else
  467. blockBegin = in_func;
  468. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  469. // 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
  470. asCParser parser(builder);
  471. int r = parser.ParseStatementBlock(script, blockBegin);
  472. if( r < 0 ) return -1;
  473. asCScriptNode *block = parser.GetScriptNode();
  474. // Reserve a label for the cleanup code
  475. nextLabel++;
  476. bool hasReturn;
  477. asCByteCode bc(engine);
  478. LineInstr(&bc, blockBegin->tokenPos);
  479. CompileStatementBlock(block, false, &hasReturn, &bc);
  480. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  481. // Make sure there is a return in all paths (if not return type is void)
  482. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  483. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  484. {
  485. if( hasReturn == false )
  486. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  487. }
  488. //------------------------------------------------
  489. // Concatenate the bytecode
  490. // Insert a JitEntry at the start of the function for JIT compilers
  491. byteCode.InstrPTR(asBC_JitEntry, 0);
  492. if( outFunc->objectType )
  493. {
  494. if( m_isConstructor )
  495. {
  496. if( outFunc->objectType->derivedFrom )
  497. {
  498. // Call the base class' default constructor unless called manually in the code
  499. if( !m_isConstructorCalled )
  500. {
  501. if( outFunc->objectType->derivedFrom->beh.construct )
  502. {
  503. // Initialize members without explicit expression first
  504. CompileMemberInitialization(&byteCode, true);
  505. // Call base class' constructor
  506. asCByteCode tmpBC(engine);
  507. tmpBC.InstrSHORT(asBC_PSF, 0);
  508. tmpBC.Instr(asBC_RDSPtr);
  509. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  510. tmpBC.OptimizeLocally(tempVariableOffsets);
  511. byteCode.AddCode(&tmpBC);
  512. // Add the initialization of the members with explicit expressions
  513. CompileMemberInitialization(&byteCode, false);
  514. }
  515. else
  516. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  517. }
  518. else
  519. {
  520. // Only initialize members that don't have an explicit expression
  521. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  522. CompileMemberInitialization(&byteCode, true);
  523. }
  524. }
  525. else
  526. {
  527. // Add the initialization of the members
  528. CompileMemberInitialization(&byteCode, true);
  529. CompileMemberInitialization(&byteCode, false);
  530. }
  531. }
  532. }
  533. // Add the code for the statement block
  534. byteCode.AddCode(&bc);
  535. // Count total variable size
  536. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  537. outFunc->scriptData->variableSpace = varSize;
  538. // Deallocate all local variables
  539. int n;
  540. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  541. {
  542. sVariable *v = variables->variables[n];
  543. if( v->stackOffset > 0 )
  544. {
  545. // Call variables destructors
  546. if( v->name != "return" )
  547. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  548. DeallocateVariable(v->stackOffset);
  549. }
  550. }
  551. // This is the label that return statements jump to
  552. // in order to exit the function
  553. byteCode.Label(0);
  554. // Call destructors for function parameters
  555. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  556. {
  557. sVariable *v = variables->variables[n];
  558. if( v->stackOffset <= 0 )
  559. {
  560. // Call variable destructors here, for variables not yet destroyed
  561. if( v->name != "return" )
  562. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  563. }
  564. // Do not deallocate parameters
  565. }
  566. // Check if the number of labels in the functions isn't too many to be handled
  567. if( nextLabel >= (1<<15) )
  568. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  569. // If there are compile errors, there is no reason to build the final code
  570. if( hasCompileErrors || builder->numErrors != buildErrors )
  571. return -1;
  572. // At this point there should be no variables allocated
  573. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  574. // Remove the variable scope
  575. RemoveVariableScope();
  576. byteCode.Ret(-stackPos);
  577. FinalizeFunction();
  578. #ifdef AS_DEBUG
  579. // DEBUG: output byte code
  580. if( outFunc->objectType )
  581. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  582. else
  583. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  584. #endif
  585. return 0;
  586. }
  587. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  588. {
  589. if( !type.IsObject() )
  590. return 0;
  591. // CallCopyConstructor should not be called for object handles.
  592. asASSERT( !type.IsObjectHandle() );
  593. asCArray<asCExprContext*> args;
  594. args.PushLast(arg);
  595. // The reference parameter must be pushed on the stack
  596. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  597. // Since we're calling the copy constructor, we have to trust the function to not do
  598. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  599. // copies of the argument in order to guarantee safety.
  600. if( type.GetTypeInfo()->flags & asOBJ_REF )
  601. {
  602. int func = 0;
  603. asSTypeBehaviour *beh = type.GetBehaviour();
  604. if( beh ) func = beh->copyfactory;
  605. if( func > 0 )
  606. {
  607. if( !isGlobalVar )
  608. {
  609. // Call factory and store the handle in the given variable
  610. PerformFunctionCall(func, ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  611. // Pop the reference left by the function call
  612. ctx->bc.Instr(asBC_PopPtr);
  613. }
  614. else
  615. {
  616. // Call factory
  617. PerformFunctionCall(func, ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  618. // Store the returned handle in the global variable
  619. ctx->bc.Instr(asBC_RDSPtr);
  620. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  621. ctx->bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  622. ctx->bc.Instr(asBC_PopPtr);
  623. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  624. }
  625. return 0;
  626. }
  627. }
  628. else
  629. {
  630. asSTypeBehaviour *beh = type.GetBehaviour();
  631. int func = beh ? beh->copyconstruct : 0;
  632. if( func > 0 )
  633. {
  634. // Push the address where the object will be stored on the stack, before the argument
  635. // TODO: When the context is serializable this probably has to be changed, since this
  636. // pointer can remain on the stack while the context is suspended. There is no
  637. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  638. asCByteCode tmp(engine);
  639. if( isGlobalVar )
  640. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  641. else if( isObjectOnHeap )
  642. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  643. MergeExprBytecode(ctx, arg);
  644. // When the object is allocated on the stack the object pointer
  645. // must be pushed on the stack after the arguments
  646. if( !isObjectOnHeap )
  647. {
  648. asASSERT( !isGlobalVar );
  649. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  650. if( derefDest )
  651. {
  652. // The variable is a reference to the real location, so we need to dereference it
  653. ctx->bc.Instr(asBC_RDSPtr);
  654. }
  655. }
  656. PerformFunctionCall(func, ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  657. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  658. // Mark the object as initialized
  659. if( !isObjectOnHeap )
  660. ctx->bc.ObjInfo(offset, asOBJ_INIT);
  661. return 0;
  662. }
  663. }
  664. // Class has no copy constructor/factory.
  665. asCString str;
  666. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  667. Error(str, node);
  668. return -1;
  669. }
  670. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  671. {
  672. if( !type.IsObject() || type.IsObjectHandle() )
  673. return 0;
  674. if( type.GetTypeInfo()->flags & asOBJ_REF )
  675. {
  676. asCExprContext ctx(engine);
  677. ctx.exprNode = node;
  678. int func = 0;
  679. asSTypeBehaviour *beh = type.GetBehaviour();
  680. if( beh )
  681. {
  682. func = beh->factory;
  683. // If no trivial default factory is found, look for a factory where all params have default args
  684. if( func == 0 )
  685. {
  686. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  687. {
  688. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  689. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  690. f->defaultArgs[0] != 0 )
  691. {
  692. func = beh->factories[n];
  693. break;
  694. }
  695. }
  696. }
  697. }
  698. if( func > 0 )
  699. {
  700. asCArray<asCExprContext *> args;
  701. asCScriptFunction *f = engine->scriptFunctions[func];
  702. if( f->parameterTypes.GetLength() )
  703. {
  704. // Add the default values for arguments not explicitly supplied
  705. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  706. PrepareFunctionCall(func, &ctx.bc, args);
  707. MoveArgsToStack(func, &ctx.bc, args, false);
  708. }
  709. if( isVarGlobOrMem == 0 )
  710. {
  711. // Call factory and store the handle in the given variable
  712. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  713. // Pop the reference left by the function call
  714. ctx.bc.Instr(asBC_PopPtr);
  715. }
  716. else
  717. {
  718. // Call factory
  719. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  720. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  721. // instead of first storing it in a local variable and then copying it to the
  722. // destination.
  723. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  724. {
  725. // Only dereference the variable if not a scoped type
  726. ctx.bc.Instr(asBC_RDSPtr);
  727. }
  728. if( isVarGlobOrMem == 1 )
  729. {
  730. // Store the returned handle in the global variable
  731. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  732. }
  733. else
  734. {
  735. // Store the returned handle in the class member
  736. ctx.bc.InstrSHORT(asBC_PSF, 0);
  737. ctx.bc.Instr(asBC_RDSPtr);
  738. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  739. }
  740. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  741. {
  742. // For scoped typed we must move the reference from the local
  743. // variable rather than copy it as there is no AddRef behaviour
  744. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  745. // Clear the local variable so the reference isn't released
  746. ctx.bc.InstrSHORT(asBC_ClrVPtr, (short)ctx.type.stackOffset);
  747. }
  748. else
  749. {
  750. if( type.IsFuncdef() )
  751. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  752. else
  753. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  754. }
  755. ctx.bc.Instr(asBC_PopPtr);
  756. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  757. }
  758. bc->AddCode(&ctx.bc);
  759. // Cleanup
  760. for( asUINT n = 0; n < args.GetLength(); n++ )
  761. if( args[n] )
  762. {
  763. asDELETE(args[n], asCExprContext);
  764. }
  765. return 0;
  766. }
  767. }
  768. else
  769. {
  770. asCExprContext ctx(engine);
  771. ctx.exprNode = node;
  772. asSTypeBehaviour *beh = type.GetBehaviour();
  773. int func = 0;
  774. if( beh )
  775. {
  776. func = beh->construct;
  777. // If no trivial default constructor is found, look for a constructor where all params have default args
  778. if( func == 0 )
  779. {
  780. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  781. {
  782. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  783. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  784. f->defaultArgs[0] != 0 )
  785. {
  786. func = beh->constructors[n];
  787. break;
  788. }
  789. }
  790. }
  791. }
  792. // Allocate and initialize with the default constructor
  793. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  794. {
  795. asCArray<asCExprContext *> args;
  796. asCScriptFunction *f = engine->scriptFunctions[func];
  797. if( f && f->parameterTypes.GetLength() )
  798. {
  799. // Add the default values for arguments not explicitly supplied
  800. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  801. PrepareFunctionCall(func, &ctx.bc, args);
  802. MoveArgsToStack(func, &ctx.bc, args, false);
  803. }
  804. if( !isObjectOnHeap )
  805. {
  806. if( isVarGlobOrMem == 0 )
  807. {
  808. // There is nothing to do if there is no function,
  809. // as the memory is already allocated on the stack
  810. if( func )
  811. {
  812. // Call the constructor as a normal function
  813. bc->InstrSHORT(asBC_PSF, (short)offset);
  814. if( derefDest )
  815. bc->Instr(asBC_RDSPtr);
  816. asCExprContext ctxCall(engine);
  817. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  818. bc->AddCode(&ctxCall.bc);
  819. }
  820. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  821. // Mark the object as initialized
  822. bc->ObjInfo(offset, asOBJ_INIT);
  823. }
  824. else if( isVarGlobOrMem == 2 )
  825. {
  826. // Only POD types can be allocated inline in script classes
  827. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  828. if( func )
  829. {
  830. // Call the constructor as a normal function
  831. bc->InstrSHORT(asBC_PSF, 0);
  832. bc->Instr(asBC_RDSPtr);
  833. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  834. asCExprContext ctxCall(engine);
  835. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  836. bc->AddCode(&ctxCall.bc);
  837. }
  838. }
  839. else
  840. {
  841. asASSERT( false );
  842. }
  843. }
  844. else
  845. {
  846. if( isVarGlobOrMem == 0 )
  847. bc->InstrSHORT(asBC_PSF, (short)offset);
  848. else if( isVarGlobOrMem == 1 )
  849. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  850. else
  851. {
  852. bc->InstrSHORT(asBC_PSF, 0);
  853. bc->Instr(asBC_RDSPtr);
  854. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  855. }
  856. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  857. {
  858. asCScriptFunction *descr = engine->scriptFunctions[func];
  859. asASSERT( descr->funcType == asFUNC_SCRIPT );
  860. // Find the id of the real constructor and not the generated stub
  861. asUINT id = 0;
  862. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  863. while( funcBc )
  864. {
  865. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  866. {
  867. id = asBC_INTARG(funcBc);
  868. break;
  869. }
  870. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  871. }
  872. asASSERT( id );
  873. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  874. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  875. }
  876. else
  877. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  878. }
  879. // Cleanup
  880. for( asUINT n = 0; n < args.GetLength(); n++ )
  881. if( args[n] )
  882. {
  883. asDELETE(args[n], asCExprContext);
  884. }
  885. return 0;
  886. }
  887. }
  888. // Class has no default factory/constructor.
  889. asCString str;
  890. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  891. Error(str, node);
  892. return -1;
  893. }
  894. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  895. {
  896. if( !type.IsReference() )
  897. {
  898. // Call destructor for the data type
  899. if( type.IsObject() || type.IsFuncdef() )
  900. {
  901. // The null pointer doesn't need to be destroyed
  902. if( type.IsNullHandle() )
  903. return;
  904. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  905. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  906. return;
  907. if( isObjectOnHeap || type.IsObjectHandle() )
  908. {
  909. // Free the memory
  910. if (type.IsFuncdef())
  911. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  912. else
  913. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  914. }
  915. else
  916. {
  917. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  918. if( type.GetBehaviour()->destruct )
  919. {
  920. // Call the destructor as a regular function
  921. asCExprContext ctx(engine);
  922. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  923. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  924. ctx.bc.OptimizeLocally(tempVariableOffsets);
  925. bc->AddCode(&ctx.bc);
  926. }
  927. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  928. // Mark the object as destroyed
  929. bc->ObjInfo(offset, asOBJ_UNINIT);
  930. }
  931. }
  932. }
  933. }
  934. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  935. {
  936. int r, c;
  937. script->ConvertPosToRowCol(pos, &r, &c);
  938. bc->Line(r, c, script->idx);
  939. }
  940. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  941. {
  942. *hasReturn = false;
  943. bool isFinished = false;
  944. bool hasUnreachableCode = false;
  945. bool hasReturnBefore = false;
  946. if( ownVariableScope )
  947. {
  948. bc->Block(true);
  949. AddVariableScope();
  950. }
  951. asCScriptNode *node = block->firstChild;
  952. while( node )
  953. {
  954. #ifdef AS_DEBUG
  955. // Keep the current line in a variable so it will be easier
  956. // to determine where in a script an assert is occurring.
  957. int currentLine = 0;
  958. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  959. #endif
  960. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  961. {
  962. // Empty statements don't count
  963. if( node->nodeType != snExpressionStatement || node->firstChild )
  964. {
  965. hasUnreachableCode = true;
  966. Warning(TXT_UNREACHABLE_CODE, node);
  967. }
  968. if( *hasReturn )
  969. hasReturnBefore = true;
  970. }
  971. if( node->nodeType == snBreak || node->nodeType == snContinue )
  972. isFinished = true;
  973. asCByteCode statement(engine);
  974. if( node->nodeType == snDeclaration )
  975. CompileDeclaration(node, &statement);
  976. else
  977. CompileStatement(node, hasReturn, &statement);
  978. // Ignore missing returns in unreachable code paths
  979. if( !(*hasReturn) && hasReturnBefore )
  980. *hasReturn = true;
  981. LineInstr(bc, node->tokenPos);
  982. bc->AddCode(&statement);
  983. if( !hasCompileErrors )
  984. {
  985. asASSERT( tempVariables.GetLength() == 0 );
  986. asASSERT( reservedVariables.GetLength() == 0 );
  987. }
  988. node = node->next;
  989. }
  990. if( ownVariableScope )
  991. {
  992. // Deallocate variables in this block, in reverse order
  993. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  994. {
  995. sVariable *v = variables->variables[n];
  996. // Call variable destructors here, for variables not yet destroyed
  997. // If the block is terminated with a break, continue, or
  998. // return the variables are already destroyed
  999. if( !isFinished && !*hasReturn )
  1000. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  1001. // Don't deallocate function parameters
  1002. if( v->stackOffset > 0 )
  1003. DeallocateVariable(v->stackOffset);
  1004. }
  1005. RemoveVariableScope();
  1006. bc->Block(false);
  1007. }
  1008. }
  1009. // Entry
  1010. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  1011. {
  1012. Reset(in_builder, in_script, in_outFunc);
  1013. m_globalVar = in_gvar;
  1014. // Add a variable scope (even though variables can't be declared)
  1015. AddVariableScope();
  1016. in_gvar->isPureConstant = false;
  1017. // Parse the initialization nodes
  1018. asCParser parser(builder);
  1019. if (in_node)
  1020. {
  1021. int r = parser.ParseVarInit(in_script, in_node);
  1022. if (r < 0)
  1023. return r;
  1024. in_node = parser.GetScriptNode();
  1025. }
  1026. asCExprContext compiledCtx(engine);
  1027. bool preCompiled = false;
  1028. if (in_gvar->datatype.IsAuto())
  1029. {
  1030. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1031. if (!preCompiled)
  1032. {
  1033. // If it wasn't possible to determine the type from the expression then there
  1034. // is no need to continue with the initialization. The error was already reported
  1035. // in CompileAutoType.
  1036. return -1;
  1037. }
  1038. }
  1039. if( in_gvar->property == 0 )
  1040. {
  1041. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1042. in_gvar->index = in_gvar->property->id;
  1043. }
  1044. // Compile the expression
  1045. asCExprContext ctx(engine);
  1046. asQWORD constantValue = 0;
  1047. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1048. {
  1049. // Should the variable be marked as pure constant?
  1050. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1051. {
  1052. in_gvar->isPureConstant = true;
  1053. in_gvar->constantValue = constantValue;
  1054. }
  1055. }
  1056. // Concatenate the bytecode
  1057. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1058. // Add information on the line number for the global variable
  1059. size_t pos = 0;
  1060. if( in_gvar->declaredAtNode )
  1061. pos = in_gvar->declaredAtNode->tokenPos;
  1062. else if( in_gvar->initializationNode )
  1063. pos = in_gvar->initializationNode->tokenPos;
  1064. LineInstr(&byteCode, pos);
  1065. // Reserve space for all local variables
  1066. outFunc->scriptData->variableSpace = varSize;
  1067. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1068. byteCode.AddCode(&ctx.bc);
  1069. // Deallocate variables in this block, in reverse order
  1070. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1071. {
  1072. sVariable *v = variables->variables[n];
  1073. // Call variable destructors here, for variables not yet destroyed
  1074. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1075. DeallocateVariable(v->stackOffset);
  1076. }
  1077. if( hasCompileErrors ) return -1;
  1078. // At this point there should be no variables allocated
  1079. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1080. // Remove the variable scope again
  1081. RemoveVariableScope();
  1082. byteCode.Ret(0);
  1083. FinalizeFunction();
  1084. #ifdef AS_DEBUG
  1085. // DEBUG: output byte code
  1086. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1087. #endif
  1088. return 0;
  1089. }
  1090. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1091. {
  1092. // Don't do anything if this is not a deferred global function
  1093. if( !ctx->IsGlobalFunc() )
  1094. return;
  1095. // Determine the namespace
  1096. asSNameSpace *ns = 0;
  1097. asCString name = "";
  1098. int pos = ctx->methodName.FindLast("::");
  1099. if( pos >= 0 )
  1100. {
  1101. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1102. // Cut off the ::
  1103. if( nsName.GetLength() > 2 )
  1104. nsName.SetLength(nsName.GetLength()-2);
  1105. ns = DetermineNameSpace(nsName);
  1106. name = ctx->methodName.SubString(pos+2);
  1107. }
  1108. else
  1109. {
  1110. DetermineNameSpace("");
  1111. name = ctx->methodName;
  1112. }
  1113. asCArray<int> funcs;
  1114. if( ns )
  1115. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1116. // CompileVariableAccess should guarantee that at least one function is exists
  1117. asASSERT( funcs.GetLength() > 0 );
  1118. if( funcs.GetLength() > 1 )
  1119. {
  1120. asCString str;
  1121. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1122. Error(str, node);
  1123. // Fall through so the compiler can continue as if only one function was matching
  1124. }
  1125. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1126. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1127. outFunc->IsShared() )
  1128. {
  1129. asCString msg;
  1130. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1131. Error(msg, node);
  1132. // Fall through so the compiler can continue anyway
  1133. }
  1134. // Push the function pointer on the stack
  1135. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1136. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1137. ctx->type.dataType.MakeHandle(true);
  1138. ctx->type.isExplicitHandle = true;
  1139. ctx->methodName = "";
  1140. }
  1141. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1142. {
  1143. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1144. // Use copy constructor if available.
  1145. asCObjectType *ot = CastToObjectType(dt.GetTypeInfo());
  1146. if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory))
  1147. {
  1148. PrepareForAssignment(&dt, arg, node, true);
  1149. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, ctx, arg, node, 0, derefDestination);
  1150. if( r < 0 && tempVariables.Exists(offset) )
  1151. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1152. }
  1153. else
  1154. {
  1155. // TODO: Need to reserve variables, as the default constructor may need
  1156. // to allocate temporary variables to compute default args
  1157. // Allocate and construct the temporary object before whatever is already in the bytecode
  1158. asCByteCode tmpBC(engine);
  1159. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1160. if( r < 0 )
  1161. {
  1162. if( tempVariables.Exists(offset) )
  1163. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1164. return;
  1165. }
  1166. tmpBC.AddCode(&ctx->bc);
  1167. ctx->bc.AddCode(&tmpBC);
  1168. // Assign the evaluated expression to the temporary variable
  1169. PrepareForAssignment(&dt, arg, node, true);
  1170. MergeExprBytecode(ctx, arg);
  1171. // Call the opAssign method to assign the value to the temporary object
  1172. dt.MakeReference(isObjectOnHeap);
  1173. asCExprValue type;
  1174. type.Set(dt);
  1175. type.isTemporary = true;
  1176. type.stackOffset = (short)offset;
  1177. if( dt.IsObjectHandle() )
  1178. type.isExplicitHandle = true;
  1179. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1180. if( derefDestination )
  1181. ctx->bc.Instr(asBC_RDSPtr);
  1182. r = PerformAssignment(&type, &arg->type, &ctx->bc, node);
  1183. if( r < 0 )
  1184. {
  1185. if( tempVariables.Exists(offset) )
  1186. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1187. return;
  1188. }
  1189. // Pop the reference that was pushed on the stack if the result is an object
  1190. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1191. ctx->bc.Instr(asBC_PopPtr);
  1192. // If the assignment operator returned an object by value it will
  1193. // be in a temporary variable which we need to destroy now
  1194. if( type.isTemporary && type.stackOffset != (short)offset )
  1195. ReleaseTemporaryVariable(type.stackOffset, &ctx->bc);
  1196. // Release the original value too in case it is a temporary
  1197. ReleaseTemporaryVariable(arg->type, &ctx->bc);
  1198. }
  1199. }
  1200. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1201. {
  1202. asCDataType param = *paramType;
  1203. if( paramType->GetTokenType() == ttQuestion )
  1204. {
  1205. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1206. DetermineSingleFunc(ctx, node);
  1207. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1208. param = ctx->type.dataType;
  1209. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1210. // Treat the void expression like a null handle when working with var types
  1211. if( ctx->IsVoidExpression() )
  1212. param = asCDataType::CreateNullHandle();
  1213. // If value assign is disabled for reference types, then make
  1214. // sure to always pass the handle to ? parameters
  1215. if( builder->engine->ep.disallowValueAssignForRefType &&
  1216. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1217. {
  1218. param.MakeHandle(true);
  1219. }
  1220. param.MakeReference(paramType->IsReference());
  1221. param.MakeReadOnly(paramType->IsReadOnly());
  1222. }
  1223. else
  1224. param = *paramType;
  1225. asCDataType dt = param;
  1226. // Need to protect arguments by reference
  1227. if( isFunction && dt.IsReference() )
  1228. {
  1229. // Allocate a temporary variable of the same type as the argument
  1230. dt.MakeReference(false);
  1231. int offset;
  1232. if( refType == asTM_INREF )
  1233. {
  1234. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1235. return -1;
  1236. // Add the type id as hidden arg if the parameter is a ? type
  1237. if( paramType->GetTokenType() == ttQuestion )
  1238. {
  1239. asCByteCode tmpBC(engine);
  1240. // Place the type id on the stack as a hidden parameter
  1241. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1242. // Insert the code before the expression code
  1243. tmpBC.AddCode(&ctx->bc);
  1244. ctx->bc.AddCode(&tmpBC);
  1245. }
  1246. if( dt.IsPrimitive() )
  1247. {
  1248. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1249. // Even if the same variable is passed in another argument as non-const then there is no problem
  1250. IsVariableInitialized(&ctx->type, node);
  1251. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1252. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1253. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1254. ConvertToTempVariable(ctx);
  1255. PushVariableOnStack(ctx, true);
  1256. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1257. }
  1258. else if( ctx->type.dataType.IsNullHandle() )
  1259. {
  1260. // Make sure the argument type can support handles (or is itself a handle)
  1261. // 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)
  1262. if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) )
  1263. {
  1264. asCString str;
  1265. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1266. Error(str, node);
  1267. ctx->type.Set(param);
  1268. return -1;
  1269. }
  1270. // Need to initialize a local temporary variable to
  1271. // represent the null handle when passed as reference
  1272. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1273. ctx->bc.Instr(asBC_PopPtr);
  1274. dt.MakeHandle(true);
  1275. dt.MakeReadOnly(false);
  1276. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1277. // Push the reference to the variable on the stack
  1278. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1279. ctx->type.SetVariable(dt, offset, true);
  1280. ctx->type.isExplicitHandle = true;
  1281. }
  1282. else
  1283. {
  1284. IsVariableInitialized(&ctx->type, node);
  1285. if( !isMakingCopy )
  1286. {
  1287. // For parameters expecting a reference to a handle we need to make sure the argument
  1288. // is really a handle, and not just a reference to the object. Do this check before the
  1289. // implicit conversion so it can be treated correctly.
  1290. if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle())
  1291. {
  1292. // Make a refCopy into a local handle variable
  1293. // Allocate a handle variable
  1294. dt.MakeHandle(true);
  1295. dt.MakeReadOnly(false);
  1296. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1297. // Copy the handle
  1298. Dereference(ctx, true);
  1299. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1300. if (ctx->type.dataType.IsFuncdef())
  1301. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1302. else
  1303. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1304. ctx->bc.Instr(asBC_PopPtr);
  1305. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1306. // Release the original temporary variable
  1307. if( ctx->type.isTemporary )
  1308. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1309. ctx->type.SetVariable(dt, offset, true);
  1310. }
  1311. // Even though the parameter expects a reference, it is only meant to be
  1312. // used as input value and doesn't have to refer to the actual object, so it
  1313. // is OK to do an implicit conversion.
  1314. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1315. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1316. {
  1317. asCString str;
  1318. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1319. Error(str, node);
  1320. ctx->type.Set(param);
  1321. return -1;
  1322. }
  1323. // The compiler must guarantee that the object stays alive during the execution
  1324. // of the function, and it must also guarantee that the value isn't modified by
  1325. // the function.
  1326. // If the argument is a temporary local variable then it is safe to be passed to
  1327. // the function as it is, since the local variable will stay alive, and since it
  1328. // is temporary there is no side effect if the function modifies it.
  1329. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1330. // function, then it is enough that the variable is local to guarantee the lifetime.
  1331. if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) )
  1332. {
  1333. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1334. {
  1335. // Funcdefs only need an extra handle to guarantee the lifetime.
  1336. // If the object is a reference type (except scoped reference types), and the
  1337. // parameter is a const reference, then it is not necessary to make a copy of the
  1338. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1339. // Allocate a handle variable
  1340. dt.MakeHandle(true);
  1341. dt.MakeReadOnly(false);
  1342. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1343. // Copy the handle
  1344. Dereference(ctx, true);
  1345. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1346. if (ctx->type.dataType.IsFuncdef())
  1347. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1348. else
  1349. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1350. ctx->bc.Instr(asBC_PopPtr);
  1351. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1352. // The type should be set to the param type instead of dt to guarantee
  1353. // that the expression keeps the correct type for variable ? args. Otherwise
  1354. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1355. bool isExplicitHandle = ctx->type.isExplicitHandle;
  1356. ctx->type.SetVariable(param, offset, true);
  1357. ctx->type.dataType.MakeHandle(true);
  1358. ctx->type.isExplicitHandle = isExplicitHandle;
  1359. }
  1360. else
  1361. {
  1362. // Make a copy of the object to guarantee that the original isn't modified
  1363. asASSERT(!dt.IsFuncdef());
  1364. // Allocate and initialize a temporary local object
  1365. dt.MakeReadOnly(false);
  1366. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1367. asCExprContext tmp(engine);
  1368. CompileInitAsCopy(dt, offset, &tmp, ctx, node, false);
  1369. MergeExprBytecode(ctx, &tmp);
  1370. // Push the object pointer on the stack
  1371. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1372. if( dt.IsObject() && !dt.IsObjectHandle() )
  1373. ctx->bc.Instr(asBC_RDSPtr);
  1374. // Set the resulting type
  1375. ctx->type.Set(dt);
  1376. ctx->type.isTemporary = true;
  1377. ctx->type.stackOffset = short(offset);
  1378. if( dt.IsObjectHandle() )
  1379. ctx->type.isExplicitHandle = true;
  1380. ctx->type.dataType.MakeReference(false);
  1381. if( paramType->IsReadOnly() )
  1382. ctx->type.dataType.MakeReadOnly(true);
  1383. }
  1384. }
  1385. // When calling a function expecting a var arg with a parameter received as reference to handle
  1386. // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
  1387. // not be able to do the correct double dereference to put the reference to the object on the stack.
  1388. if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
  1389. {
  1390. sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
  1391. if (var && var->type.IsReference() && var->type.IsObjectHandle())
  1392. {
  1393. // Copy the handle to local variable
  1394. // Allocate a handle variable
  1395. dt.MakeHandle(true);
  1396. dt.MakeReadOnly(false);
  1397. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1398. // Copy the handle
  1399. Dereference(ctx, true);
  1400. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1401. if (ctx->type.dataType.IsFuncdef())
  1402. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1403. else
  1404. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1405. ctx->bc.Instr(asBC_PopPtr);
  1406. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1407. // The type should be set to the param type instead of dt to guarantee
  1408. // that the expression keeps the correct type for variable ? args. Otherwise
  1409. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1410. ctx->type.SetVariable(param, offset, true);
  1411. }
  1412. }
  1413. }
  1414. else
  1415. {
  1416. // We must guarantee that the address to the value is on the stack
  1417. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1418. !ctx->type.dataType.IsObjectHandle() &&
  1419. ctx->type.dataType.IsReference() )
  1420. Dereference(ctx, true);
  1421. }
  1422. }
  1423. }
  1424. else if( refType == asTM_OUTREF )
  1425. {
  1426. // Add the type id as hidden arg if the parameter is a ? type
  1427. if( paramType->GetTokenType() == ttQuestion )
  1428. {
  1429. asCByteCode tmpBC(engine);
  1430. // Place the type id on the stack as a hidden parameter
  1431. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1432. // Insert the code before the expression code
  1433. tmpBC.AddCode(&ctx->bc);
  1434. ctx->bc.AddCode(&tmpBC);
  1435. }
  1436. // If the expression is marked as clean, then it can be used directly
  1437. // without the need to allocate another temporary value as it is known
  1438. // that the argument has no other value than the default
  1439. if( ctx->isCleanArg )
  1440. {
  1441. // Must be a local variable
  1442. asASSERT( ctx->type.isVariable );
  1443. }
  1444. else
  1445. {
  1446. // Null handles and void expressions must be marked as explicit
  1447. // handles for correct treatement in MoveArgsToStack
  1448. if (dt.IsNullHandle())
  1449. ctx->type.isExplicitHandle = true;
  1450. // Make sure the variable is not used in the expression
  1451. dt.MakeReadOnly(false);
  1452. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1453. if( dt.IsPrimitive() )
  1454. {
  1455. ctx->type.SetVariable(dt, offset, true);
  1456. PushVariableOnStack(ctx, true);
  1457. }
  1458. else
  1459. {
  1460. // Allocate and construct the temporary object
  1461. asCByteCode tmpBC(engine);
  1462. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1463. // Insert the code before the expression code
  1464. tmpBC.AddCode(&ctx->bc);
  1465. ctx->bc.AddCode(&tmpBC);
  1466. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1467. asCExprValue type;
  1468. type.Set(dt);
  1469. type.isTemporary = true;
  1470. type.stackOffset = (short)offset;
  1471. type.isExplicitHandle = ctx->type.isExplicitHandle;
  1472. ctx->type = type;
  1473. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1474. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1475. ctx->bc.Instr(asBC_RDSPtr);
  1476. }
  1477. // After the function returns the temporary variable will
  1478. // be assigned to the expression, if it is a valid lvalue
  1479. }
  1480. }
  1481. else if( refType == asTM_INOUTREF )
  1482. {
  1483. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1484. return -1;
  1485. // Add the type id as hidden arg if the parameter is a ? type
  1486. if( paramType->GetTokenType() == ttQuestion )
  1487. {
  1488. asCByteCode tmpBC(engine);
  1489. // Place the type id on the stack as a hidden parameter
  1490. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1491. // Insert the code before the expression code
  1492. tmpBC.AddCode(&ctx->bc);
  1493. ctx->bc.AddCode(&tmpBC);
  1494. }
  1495. // Literal constants cannot be passed to inout ref arguments
  1496. if( !ctx->type.isVariable &&
  1497. ctx->type.isConstant &&
  1498. !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
  1499. {
  1500. // Unless unsafe references are turned on and the reference is const
  1501. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1502. {
  1503. // Since the parameter is a const & make a copy.
  1504. ConvertToTempVariable(ctx);
  1505. ctx->type.dataType.MakeReadOnly(true);
  1506. }
  1507. else
  1508. {
  1509. Error(TXT_NOT_VALID_REFERENCE, node);
  1510. return -1;
  1511. }
  1512. }
  1513. // Allow anonymous init lists to be converted to the arg type
  1514. if( ctx->IsAnonymousInitList() )
  1515. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true);
  1516. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1517. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1518. // Only objects that support object handles
  1519. // can be guaranteed to be safe. Local variables are
  1520. // already safe, so there is no need to add an extra
  1521. // references
  1522. if( !engine->ep.allowUnsafeReferences &&
  1523. !ctx->type.isVariable &&
  1524. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1525. !ctx->type.dataType.IsObjectHandle() &&
  1526. ((ctx->type.dataType.GetBehaviour()->addref &&
  1527. ctx->type.dataType.GetBehaviour()->release) ||
  1528. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1529. ctx->type.dataType.IsFuncdef()) )
  1530. {
  1531. // Store a handle to the object as local variable
  1532. asCExprContext tmp(engine);
  1533. dt = ctx->type.dataType;
  1534. dt.MakeHandle(true);
  1535. dt.MakeReference(false);
  1536. dt.MakeReadOnly(false);
  1537. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1538. // Copy the handle
  1539. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1540. ctx->bc.Instr(asBC_RDSPtr);
  1541. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1542. if( ctx->type.dataType.IsFuncdef() )
  1543. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1544. else
  1545. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1546. ctx->bc.Instr(asBC_PopPtr);
  1547. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1548. dt.MakeHandle(false);
  1549. dt.MakeReference(true);
  1550. // Release previous temporary variable stored in the context (if any)
  1551. if( ctx->type.isTemporary )
  1552. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1553. ctx->type.SetVariable(dt, offset, true);
  1554. }
  1555. // Make sure the reference to the value is on the stack
  1556. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1557. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1558. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1559. Dereference(ctx, true);
  1560. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1561. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  1562. else if( ctx->type.dataType.IsPrimitive() )
  1563. ctx->bc.Instr(asBC_PshRPtr);
  1564. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1565. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1566. }
  1567. }
  1568. else
  1569. {
  1570. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1571. return -1;
  1572. if( dt.IsPrimitive() )
  1573. {
  1574. IsVariableInitialized(&ctx->type, node);
  1575. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1576. // Implicitly convert primitives to the parameter type
  1577. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1578. if( ctx->type.isVariable )
  1579. {
  1580. PushVariableOnStack(ctx, dt.IsReference());
  1581. }
  1582. else if( ctx->type.isConstant )
  1583. {
  1584. ConvertToVariable(ctx);
  1585. PushVariableOnStack(ctx, dt.IsReference());
  1586. }
  1587. }
  1588. else
  1589. {
  1590. IsVariableInitialized(&ctx->type, node);
  1591. // Implicitly convert primitives to the parameter type
  1592. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1593. // Was the conversion successful?
  1594. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1595. {
  1596. asCString str;
  1597. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1598. Error(str, node);
  1599. ctx->type.Set(dt);
  1600. return -1;
  1601. }
  1602. if( dt.IsObjectHandle() )
  1603. ctx->type.isExplicitHandle = true;
  1604. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1605. {
  1606. // Objects passed by value must be placed in temporary variables
  1607. // so that they are guaranteed to not be referenced anywhere else.
  1608. // The object must also be allocated on the heap, as the memory will
  1609. // be deleted by the called function.
  1610. // Handles passed by value must also be placed in a temporary variable
  1611. // to guarantee that the object referred to isn't freed too early.
  1612. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1613. // Don't make temporary copies of handles if it is going to be used
  1614. // for handle assignment anyway, i.e. REFCPY, except if the variable is for a @&
  1615. // parameter in which case the GETOBJREF won't be able to dereference the object handle
  1616. // TODO: optimize: This would be more efficient if it avoided the use of VAR/GETOBJREF all together
  1617. sVariable* var = ctx->type.isVariable ? variables->GetVariableByOffset(ctx->type.stackOffset) : 0;
  1618. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) ||
  1619. (var && var->type.IsReference() && var->type.IsObjectHandle()) )
  1620. PrepareTemporaryVariable(node, ctx, true);
  1621. }
  1622. }
  1623. }
  1624. // Don't put any pointer on the stack yet
  1625. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1626. {
  1627. // &inout parameter may leave the reference on the stack already
  1628. // references considered safe too, i.e. when the life time is known
  1629. if( refType != asTM_INOUTREF && !ctx->type.isRefSafe )
  1630. {
  1631. asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy );
  1632. if( ctx->type.isVariable || ctx->type.isTemporary )
  1633. {
  1634. ctx->bc.Instr(asBC_PopPtr);
  1635. ctx->bc.InstrSHORT(asBC_VAR, (short)ctx->type.stackOffset);
  1636. ProcessDeferredParams(ctx);
  1637. }
  1638. }
  1639. }
  1640. return 0;
  1641. }
  1642. int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1643. {
  1644. // When a match has been found, compile the final byte code using correct parameter types
  1645. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1646. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1647. // If the function being called is the opAssign or copy constructor for the same type
  1648. // as the argument, then we should avoid making temporary copy of the argument
  1649. bool makingCopy = false;
  1650. if( descr->parameterTypes.GetLength() == 1 &&
  1651. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1652. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1653. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1654. makingCopy = true;
  1655. // Add code for arguments
  1656. asCExprContext e(engine);
  1657. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1658. {
  1659. // Make sure PrepareArgument doesn't use any variable that is already
  1660. // being used by the argument or any of the following argument expressions
  1661. int l = int(reservedVariables.GetLength());
  1662. for( int m = n; m >= 0; m-- )
  1663. args[m]->bc.GetVarsUsed(reservedVariables);
  1664. int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1665. reservedVariables.SetLength(l);
  1666. if (r < 0)
  1667. return r;
  1668. }
  1669. bc->AddCode(&e.bc);
  1670. return 0;
  1671. }
  1672. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1673. {
  1674. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1675. int offset = 0;
  1676. if( addOneToOffset )
  1677. offset += AS_PTR_SIZE;
  1678. // The address of where the return value should be stored is push on top of the arguments
  1679. if( descr->DoesReturnOnStack() )
  1680. offset += AS_PTR_SIZE;
  1681. #ifdef AS_DEBUG
  1682. // If the function being called is the opAssign or copy constructor for the same type
  1683. // as the argument, then we should avoid making temporary copy of the argument
  1684. bool makingCopy = false;
  1685. if( descr->parameterTypes.GetLength() == 1 &&
  1686. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1687. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1688. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1689. makingCopy = true;
  1690. #endif
  1691. // Move the objects that are sent by value to the stack just before the call
  1692. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1693. {
  1694. if( descr->parameterTypes[n].IsReference() )
  1695. {
  1696. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1697. {
  1698. if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe )
  1699. {
  1700. #ifdef AS_DEBUG
  1701. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1702. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1703. #endif
  1704. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1705. {
  1706. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1707. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1708. // as the value allocated on the stack is guaranteed to be safe
  1709. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1710. else
  1711. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1712. }
  1713. }
  1714. if( args[n]->type.dataType.IsObjectHandle() )
  1715. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1716. }
  1717. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1718. {
  1719. // If the argument is already known to be safe, i.e. has a guaranteed lifetime,
  1720. // then the address on the stack is already pointing to the correct object so no
  1721. // need to do anything else
  1722. if (!args[n]->type.isRefSafe)
  1723. {
  1724. if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1725. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1726. !args[n]->type.dataType.IsObjectHandle())
  1727. {
  1728. // Send the object as a reference to the object,
  1729. // and not to the variable holding the object
  1730. if (!IsVariableOnHeap(args[n]->type.stackOffset))
  1731. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1732. // as the value allocated on the stack is guaranteed to be safe
  1733. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1734. else
  1735. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1736. }
  1737. else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1738. args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
  1739. {
  1740. // The object handle is being passed as an object, so dereference it before
  1741. // the call so the reference will be to the object rather than to the handle
  1742. if (engine->ep.disallowValueAssignForRefType)
  1743. {
  1744. // With disallow value assign all ref type objects are always passed by handle
  1745. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1746. }
  1747. else
  1748. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1749. }
  1750. else
  1751. {
  1752. // If the variable is really an argument of @& type, then it is necessary
  1753. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1754. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1755. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1756. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1757. else
  1758. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1759. }
  1760. }
  1761. }
  1762. }
  1763. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1764. {
  1765. asASSERT(!args[n]->type.isRefSafe);
  1766. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1767. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1768. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1769. // The pointer in the variable will be moved to the stack
  1770. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1771. // Deallocate the variable slot so it can be reused, but do not attempt to
  1772. // free the content of the variable since it was moved to the stack for the call
  1773. DeallocateVariable(args[n]->type.stackOffset);
  1774. args[n]->type.isTemporary = false;
  1775. }
  1776. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1777. }
  1778. }
  1779. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1780. {
  1781. asASSERT(node->nodeType == snArgList);
  1782. // Count arguments
  1783. asCScriptNode *arg = node->firstChild;
  1784. int argCount = 0;
  1785. while( arg )
  1786. {
  1787. if( arg->nodeType != snNamedArgument )
  1788. argCount++;
  1789. arg = arg->next;
  1790. }
  1791. // Prepare the arrays
  1792. args.SetLength(argCount);
  1793. int n;
  1794. for( n = 0; n < argCount; n++ )
  1795. args[n] = 0;
  1796. n = argCount-1;
  1797. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1798. bool anyErrors = false, inPositionalArguments = false;
  1799. arg = node->lastChild;
  1800. while( arg )
  1801. {
  1802. asCScriptNode *asgNode = arg, *namedNode = 0;
  1803. if( asgNode->nodeType == snNamedArgument )
  1804. {
  1805. if( inPositionalArguments )
  1806. {
  1807. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1808. return -1;
  1809. }
  1810. asgNode = arg->firstChild->next;
  1811. namedNode = arg->firstChild;
  1812. asASSERT( namedNode->nodeType == snIdentifier );
  1813. }
  1814. else
  1815. inPositionalArguments = true;
  1816. asCExprContext expr(engine);
  1817. int r = CompileAssignment(asgNode, &expr);
  1818. if( r < 0 ) anyErrors = true;
  1819. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1820. if( ctx == 0 )
  1821. {
  1822. // Out of memory
  1823. return -1;
  1824. }
  1825. MergeExprBytecodeAndType(ctx, &expr);
  1826. if( inPositionalArguments )
  1827. {
  1828. args[n] = ctx;
  1829. n--;
  1830. }
  1831. else
  1832. {
  1833. asSNamedArgument namedArg;
  1834. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1835. namedArg.ctx = ctx;
  1836. // Error out when multiple arguments with the same name are passed
  1837. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1838. {
  1839. if( namedArgs[a].name == namedArg.name )
  1840. {
  1841. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1842. anyErrors = true;
  1843. break;
  1844. }
  1845. }
  1846. namedArgs.PushLast(namedArg);
  1847. }
  1848. arg = arg->prev;
  1849. }
  1850. return anyErrors ? -1 : 0;
  1851. }
  1852. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1853. {
  1854. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1855. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1856. return 0;
  1857. // Make sure to use the real function for virtual functions
  1858. if( func->funcType == asFUNC_VIRTUAL )
  1859. {
  1860. asASSERT( objectType );
  1861. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1862. }
  1863. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1864. bool anyErrors = false;
  1865. int prevReservedVars = reservedVariables.GetLength();
  1866. int explicitArgs = (int)args.GetLength();
  1867. for( int p = 0; p < explicitArgs; p++ )
  1868. args[p]->bc.GetVarsUsed(reservedVariables);
  1869. // Make space for all the new arguments
  1870. args.SetLength(func->parameterTypes.GetLength());
  1871. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1872. args[c] = 0;
  1873. // Add the named arguments to the argument list in the right position
  1874. if( namedArgs )
  1875. {
  1876. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1877. {
  1878. asSNamedArgument &named = (*namedArgs)[n];
  1879. named.ctx->bc.GetVarsUsed(reservedVariables);
  1880. // Find the right spot to put it in
  1881. asUINT index = asUINT(-1);
  1882. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1883. {
  1884. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1885. {
  1886. index = j;
  1887. break;
  1888. }
  1889. }
  1890. asASSERT( index < args.GetLength() );
  1891. args[index] = named.ctx;
  1892. named.ctx = 0;
  1893. }
  1894. }
  1895. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1896. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1897. {
  1898. if( args[n] != 0 ) continue;
  1899. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1900. // Parse the default arg string
  1901. asCParser parser(builder);
  1902. asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength());
  1903. int r = parser.ParseExpression(code);
  1904. if( r < 0 )
  1905. {
  1906. asCString msg;
  1907. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1908. Error(msg, node);
  1909. anyErrors = true;
  1910. continue;
  1911. }
  1912. asCScriptNode *arg = parser.GetScriptNode();
  1913. // Temporarily set the script code to the default arg expression
  1914. asCScriptCode *origScript = script;
  1915. script = code;
  1916. // Don't allow the expression to access local variables
  1917. isCompilingDefaultArg = true;
  1918. // Temporarily set the namespace in the output function to the namespace of the called
  1919. // function so that the default arguments are evaluated in the correct namespace
  1920. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1921. outFunc->nameSpace = func->nameSpace;
  1922. asCExprContext expr(engine);
  1923. r = CompileExpression(arg, &expr);
  1924. // Restore the namespace
  1925. outFunc->nameSpace = origNameSpace;
  1926. // Don't allow address of class method
  1927. if( expr.IsClassMethod() )
  1928. {
  1929. // TODO: Improve error message
  1930. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1931. r = -1;
  1932. }
  1933. // Make sure the expression can be implicitly converted to the parameter type
  1934. if( r >= 0 )
  1935. {
  1936. asCArray<int> funcs;
  1937. funcs.PushLast(func->id);
  1938. asCArray<asSOverloadCandidate> matches;
  1939. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1940. {
  1941. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1942. r = -1;
  1943. }
  1944. }
  1945. isCompilingDefaultArg = false;
  1946. script = origScript;
  1947. if( r < 0 )
  1948. {
  1949. asCString msg;
  1950. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1951. Error(msg, node);
  1952. anyErrors = true;
  1953. continue;
  1954. }
  1955. args[n] = asNEW(asCExprContext)(engine);
  1956. if( args[n] == 0 )
  1957. {
  1958. // Out of memory
  1959. reservedVariables.SetLength(prevReservedVars);
  1960. return -1;
  1961. }
  1962. MergeExprBytecodeAndType(args[n], &expr);
  1963. if (args[n]->exprNode)
  1964. {
  1965. // Disconnect the node from the parser, and tell the compiler to free it when complete
  1966. args[n]->exprNode->DisconnectParent();
  1967. nodesToFreeUponComplete.PushLast(args[n]->exprNode);
  1968. }
  1969. }
  1970. reservedVariables.SetLength(prevReservedVars);
  1971. return anyErrors ? -1 : 0;
  1972. }
  1973. 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)
  1974. {
  1975. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1976. asUINT cost = 0;
  1977. asUINT n;
  1978. if( funcs.GetLength() > 0 )
  1979. {
  1980. // Check the number of parameters in the found functions
  1981. asUINT totalArgs = (asUINT)args.GetLength();
  1982. if( namedArgs != 0 )
  1983. totalArgs += (asUINT)namedArgs->GetLength();
  1984. for( n = 0; n < funcs.GetLength(); ++n )
  1985. {
  1986. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1987. if( desc->parameterTypes.GetLength() != totalArgs )
  1988. {
  1989. bool noMatch = true;
  1990. if( totalArgs < desc->parameterTypes.GetLength() )
  1991. {
  1992. // For virtual functions, the default args are defined in the real function of the object
  1993. if( desc->funcType == asFUNC_VIRTUAL )
  1994. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1995. // Count the number of default args
  1996. asUINT defaultArgs = 0;
  1997. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1998. if( desc->defaultArgs[d] )
  1999. defaultArgs++;
  2000. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  2001. noMatch = false;
  2002. }
  2003. if( noMatch )
  2004. {
  2005. // remove it from the list
  2006. if( n == funcs.GetLength()-1 )
  2007. funcs.PopLast();
  2008. else
  2009. funcs[n] = funcs.PopLast();
  2010. n--;
  2011. }
  2012. }
  2013. }
  2014. // Match functions with the parameters, and discard those that do not match
  2015. asCArray<asSOverloadCandidate> matchingFuncs;
  2016. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  2017. for ( n = 0; n < funcs.GetLength(); ++n )
  2018. {
  2019. matchingFuncs[n].funcId = funcs[n];
  2020. matchingFuncs[n].cost = 0;
  2021. }
  2022. // Match positionally passed arguments
  2023. for( n = 0; n < args.GetLength(); ++n )
  2024. {
  2025. asCArray<asSOverloadCandidate> tempFuncs;
  2026. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  2027. // Intersect the found functions with the list of matching functions
  2028. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  2029. {
  2030. asUINT c;
  2031. for( c = 0; c < tempFuncs.GetLength(); c++ )
  2032. {
  2033. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  2034. {
  2035. // Sum argument cost
  2036. matchingFuncs[f].cost += tempFuncs[c].cost;
  2037. break;
  2038. } // End if match
  2039. }
  2040. // Was the function a match?
  2041. if( c == tempFuncs.GetLength() )
  2042. {
  2043. // No, remove it from the list
  2044. if( f == matchingFuncs.GetLength()-1 )
  2045. matchingFuncs.PopLast();
  2046. else
  2047. matchingFuncs[f] = matchingFuncs.PopLast();
  2048. f--;
  2049. }
  2050. }
  2051. }
  2052. // Match named arguments
  2053. if( namedArgs != 0 )
  2054. {
  2055. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  2056. {
  2057. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  2058. if( desc->funcType == asFUNC_VIRTUAL )
  2059. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  2060. // Match every named argument to an argument in the function
  2061. for( n = 0; n < namedArgs->GetLength(); ++n )
  2062. (*namedArgs)[n].match = asUINT(-1);
  2063. bool matchedAll = true;
  2064. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  2065. {
  2066. asUINT match = asUINT(-1);
  2067. for( n = 0; n < namedArgs->GetLength(); ++n )
  2068. {
  2069. asSNamedArgument &namedArg = (*namedArgs)[n];
  2070. if( desc->parameterNames[j] == namedArg.name )
  2071. {
  2072. namedArg.match = j;
  2073. match = n;
  2074. break;
  2075. }
  2076. }
  2077. // Check that every position is filled somehow
  2078. if( j >= args.GetLength() )
  2079. {
  2080. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  2081. {
  2082. // No argument was found for this, and there is no
  2083. // default, so it doesn't work.
  2084. matchedAll = false;
  2085. break;
  2086. }
  2087. }
  2088. else
  2089. {
  2090. if( match != asUINT(-1) )
  2091. {
  2092. // Can't name an argument that was already passed
  2093. matchedAll = false;
  2094. break;
  2095. }
  2096. }
  2097. }
  2098. // Check that every named argument was matched
  2099. if( matchedAll )
  2100. {
  2101. for( n = 0; n < namedArgs->GetLength(); ++n )
  2102. {
  2103. asSNamedArgument &named = (*namedArgs)[n];
  2104. if( named.match == asUINT(-1) )
  2105. {
  2106. matchedAll = false;
  2107. break;
  2108. }
  2109. // Add to the cost
  2110. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  2111. if( cost == asUINT(-1) )
  2112. {
  2113. matchedAll = false;
  2114. break;
  2115. }
  2116. matchingFuncs[i].cost += cost;
  2117. }
  2118. }
  2119. if( !matchedAll )
  2120. {
  2121. // Remove the function, we didn't match all the arguments.
  2122. if( i == matchingFuncs.GetLength()-1 )
  2123. matchingFuncs.PopLast();
  2124. else
  2125. matchingFuncs[i] = matchingFuncs.PopLast();
  2126. i--;
  2127. }
  2128. }
  2129. }
  2130. // Select the overload(s) with the lowest overall cost
  2131. funcs.SetLength(0);
  2132. asUINT bestCost = asUINT(-1);
  2133. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2134. {
  2135. cost = matchingFuncs[n].cost;
  2136. if( cost < bestCost )
  2137. {
  2138. funcs.SetLength(0);
  2139. bestCost = cost;
  2140. }
  2141. if( cost == bestCost )
  2142. funcs.PushLast( matchingFuncs[n].funcId );
  2143. }
  2144. // Cost returned is equivalent to the best cost discovered
  2145. cost = bestCost;
  2146. }
  2147. if( !isConstMethod )
  2148. FilterConst(funcs);
  2149. if( funcs.GetLength() != 1 && !silent )
  2150. {
  2151. // Build a readable string of the function with parameter types
  2152. bool attemptsPassingClassMethod = false;
  2153. asCString str;
  2154. if( scope != "" && scope != "::" )
  2155. str = scope + "::";
  2156. str += name;
  2157. str += "(";
  2158. for( n = 0; n < args.GetLength(); n++ )
  2159. {
  2160. if( n > 0 )
  2161. str += ", ";
  2162. if( args[n]->methodName != "" )
  2163. {
  2164. if( args[n]->IsClassMethod() )
  2165. {
  2166. attemptsPassingClassMethod = true;
  2167. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2168. str += "::";
  2169. }
  2170. str += args[n]->methodName;
  2171. }
  2172. else if (args[n]->IsAnonymousInitList())
  2173. {
  2174. str += "{...}";
  2175. }
  2176. else
  2177. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2178. }
  2179. if( namedArgs != 0 )
  2180. {
  2181. for( n = 0; n < namedArgs->GetLength(); n++ )
  2182. {
  2183. if( n > 0 || args.GetLength() )
  2184. str += ", ";
  2185. asSNamedArgument &named = (*namedArgs)[n];
  2186. str += named.name;
  2187. str += ": ";
  2188. if( named.ctx->methodName != "" )
  2189. str += named.ctx->methodName;
  2190. else
  2191. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2192. }
  2193. }
  2194. str += ")";
  2195. if( isConstMethod )
  2196. str += " const";
  2197. if( objectType && scope == "" )
  2198. str = objectType->name + "::" + str;
  2199. if( funcs.GetLength() == 0 )
  2200. {
  2201. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2202. Error(str, node);
  2203. if( attemptsPassingClassMethod )
  2204. {
  2205. // Class methods must use delegate objects
  2206. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2207. }
  2208. else
  2209. {
  2210. // Print the list of candidates
  2211. if( origFuncs.GetLength() > 0 )
  2212. {
  2213. int r = 0, c = 0;
  2214. asASSERT( node );
  2215. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2216. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2217. PrintMatchingFuncs(origFuncs, node, objectType);
  2218. }
  2219. }
  2220. }
  2221. else
  2222. {
  2223. asASSERT( attemptsPassingClassMethod == false );
  2224. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2225. Error(str, node);
  2226. PrintMatchingFuncs(funcs, node, objectType);
  2227. }
  2228. }
  2229. return cost;
  2230. }
  2231. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2232. {
  2233. if( node && node->nodeType == snAssignment )
  2234. {
  2235. int r = CompileAssignment(node, &compiledCtx);
  2236. if( r >= 0 )
  2237. {
  2238. // Must not have unused ambiguous names
  2239. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2240. {
  2241. // TODO: Should mention that the problem is the ambiguous name
  2242. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2243. return false;
  2244. }
  2245. // Must not have unused anonymous functions
  2246. if (compiledCtx.IsLambda())
  2247. {
  2248. // TODO: Should mention that the problem is the anonymous function
  2249. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2250. return false;
  2251. }
  2252. // Must not be a null handle
  2253. if (compiledCtx.type.dataType.IsNullHandle())
  2254. {
  2255. // TODO: Should mention that the problem is the null pointer
  2256. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2257. return false;
  2258. }
  2259. asCDataType newType = compiledCtx.type.dataType;
  2260. // Handle const qualifier on auto
  2261. if (type.IsReadOnly())
  2262. newType.MakeReadOnly(true);
  2263. else if (type.IsHandleToConst())
  2264. newType.MakeHandleToConst(true);
  2265. else if (newType.IsPrimitive())
  2266. newType.MakeReadOnly(false);
  2267. // Handle reference/value stuff
  2268. newType.MakeReference(false);
  2269. if (!newType.IsObjectHandle())
  2270. {
  2271. // We got a value object or an object reference.
  2272. // Turn the variable into a handle if specified
  2273. // as auto@, otherwise make it a 'value'.
  2274. if (type.IsHandleToAuto())
  2275. {
  2276. if (newType.MakeHandle(true) < 0)
  2277. {
  2278. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2279. return false;
  2280. }
  2281. }
  2282. }
  2283. // Implicit handle types should always be handles
  2284. if (newType.GetTypeInfo() &&
  2285. (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
  2286. newType.MakeHandle(true);
  2287. // For types that support handles auto should prefer handle
  2288. // as it is more efficient than making a copy
  2289. if( newType.SupportHandles() )
  2290. newType.MakeHandle(true);
  2291. type = newType;
  2292. return true;
  2293. }
  2294. return false;
  2295. }
  2296. else
  2297. {
  2298. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2299. type = asCDataType::CreatePrimitive(ttInt, false);
  2300. return false;
  2301. }
  2302. }
  2303. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2304. {
  2305. // Get the data type
  2306. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2307. // Declare all variables in this declaration
  2308. asCScriptNode *node = decl->firstChild->next;
  2309. while( node )
  2310. {
  2311. // If this is an auto type, we have to compile the assignment now to figure out the type
  2312. asCExprContext compiledCtx(engine);
  2313. bool preCompiled = false;
  2314. if (type.IsAuto())
  2315. {
  2316. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2317. if (!preCompiled)
  2318. {
  2319. // If it wasn't possible to determine the type from the expression then there
  2320. // is no need to continue with the initialization. The error was already reported
  2321. // in CompileAutoType.
  2322. return;
  2323. }
  2324. }
  2325. // Is the type allowed?
  2326. if( !type.CanBeInstantiated() )
  2327. {
  2328. asCString str;
  2329. if( type.IsAbstractClass() )
  2330. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2331. else if( type.IsInterface() )
  2332. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2333. else
  2334. // TODO: Improve error message to explain why
  2335. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2336. Error(str, node);
  2337. // Don't continue, as it will most likely lead to further
  2338. // errors that may just mislead the script writer
  2339. return;
  2340. }
  2341. // A shared object may not declare variables of non-shared types
  2342. if( outFunc->IsShared() )
  2343. {
  2344. asCTypeInfo *ot = type.GetTypeInfo();
  2345. if( ot && !ot->IsShared() )
  2346. {
  2347. asCString msg;
  2348. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2349. Error(msg, decl);
  2350. }
  2351. }
  2352. // Get the name of the identifier
  2353. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2354. // Verify that the name isn't used by a dynamic data type
  2355. // TODO: Must check against registered funcdefs too
  2356. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2357. {
  2358. asCString str;
  2359. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2360. Error(str, node);
  2361. }
  2362. int offset = AllocateVariable(type, false);
  2363. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2364. {
  2365. // TODO: It might be an out-of-memory too
  2366. asCString str;
  2367. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2368. Error(str, node);
  2369. // Don't continue after this error, as it will just
  2370. // lead to more errors that are likely false
  2371. return;
  2372. }
  2373. else
  2374. {
  2375. // Warn if this variable hides another variable in a higher scope
  2376. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2377. {
  2378. asCString str;
  2379. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2380. Warning(str, node);
  2381. }
  2382. }
  2383. // Add marker that the variable has been declared
  2384. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2385. outFunc->AddVariable(name, type, offset, IsVariableOnHeap(offset));
  2386. // Keep the node for the variable decl
  2387. asCScriptNode *varNode = node;
  2388. node = node->next;
  2389. if( node == 0 || node->nodeType == snIdentifier )
  2390. {
  2391. // Initialize with default constructor
  2392. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2393. }
  2394. else
  2395. {
  2396. // Compile the initialization expression
  2397. asQWORD constantValue = 0;
  2398. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2399. {
  2400. // Check if the variable should be marked as pure constant
  2401. if( type.IsPrimitive() && type.IsReadOnly() )
  2402. {
  2403. sVariable *v = variables->GetVariable(name.AddressOf());
  2404. v->isPureConstant = true;
  2405. v->constantValue = constantValue;
  2406. }
  2407. }
  2408. node = node->next;
  2409. }
  2410. }
  2411. bc->OptimizeLocally(tempVariableOffsets);
  2412. }
  2413. // Returns true if the initialization expression is a constant expression
  2414. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2415. {
  2416. bool isConstantExpression = false;
  2417. if( node && node->nodeType == snArgList )
  2418. {
  2419. // Make sure it is an object and not a handle
  2420. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2421. {
  2422. Error(TXT_MUST_BE_OBJECT, node);
  2423. }
  2424. else
  2425. {
  2426. // Compile the arguments
  2427. asCArray<asCExprContext *> args;
  2428. asCArray<asSNamedArgument> namedArgs;
  2429. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2430. {
  2431. // Find all constructors
  2432. asCArray<int> funcs;
  2433. asSTypeBehaviour *beh = type.GetBehaviour();
  2434. if( beh )
  2435. {
  2436. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2437. funcs = beh->factories;
  2438. else
  2439. funcs = beh->constructors;
  2440. }
  2441. asCString str = type.Format(outFunc->nameSpace);
  2442. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2443. if( funcs.GetLength() == 1 )
  2444. {
  2445. // Add the default values for arguments not explicitly supplied
  2446. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2447. if( r == asSUCCESS )
  2448. {
  2449. asCExprContext ctx(engine);
  2450. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2451. {
  2452. if( isVarGlobOrMem == 0 )
  2453. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2454. else
  2455. {
  2456. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2457. ctx.bc.Instr(asBC_RDSPtr);
  2458. if( isVarGlobOrMem == 1 )
  2459. {
  2460. // Store the returned handle in the global variable
  2461. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2462. }
  2463. else
  2464. {
  2465. // Store the returned handle in the member
  2466. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2467. ctx.bc.Instr(asBC_RDSPtr);
  2468. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2469. }
  2470. if( type.IsFuncdef())
  2471. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2472. else
  2473. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2474. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2475. }
  2476. // Pop the reference left by the function call
  2477. ctx.bc.Instr(asBC_PopPtr);
  2478. }
  2479. else
  2480. {
  2481. bool onHeap = false;
  2482. if( isVarGlobOrMem == 0 )
  2483. {
  2484. // When the object is allocated on the heap, the address where the
  2485. // reference will be stored must be pushed on the stack before the
  2486. // arguments. This reference on the stack is safe, even if the script
  2487. // is suspended during the evaluation of the arguments.
  2488. onHeap = IsVariableOnHeap(offset);
  2489. if( onHeap )
  2490. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2491. }
  2492. else if( isVarGlobOrMem == 1 )
  2493. {
  2494. // Push the address of the location where the variable will be stored on the stack.
  2495. // This reference is safe, because the addresses of the global variables cannot change.
  2496. onHeap = true;
  2497. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2498. }
  2499. else
  2500. {
  2501. // Value types may be allocated inline if they are POD types
  2502. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2503. if( onHeap )
  2504. {
  2505. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2506. ctx.bc.Instr(asBC_RDSPtr);
  2507. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2508. }
  2509. }
  2510. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2511. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2512. // When the object is allocated on the stack, the address to the
  2513. // object is pushed on the stack after the arguments as the object pointer
  2514. if( !onHeap )
  2515. {
  2516. if( isVarGlobOrMem == 2 )
  2517. {
  2518. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2519. ctx.bc.Instr(asBC_RDSPtr);
  2520. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2521. }
  2522. else
  2523. {
  2524. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2525. }
  2526. }
  2527. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2528. if( isVarGlobOrMem == 0 )
  2529. {
  2530. // Mark the object in the local variable as initialized
  2531. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2532. }
  2533. }
  2534. ProcessDeferredParams(&ctx);
  2535. bc->AddCode(&ctx.bc);
  2536. }
  2537. }
  2538. }
  2539. // Cleanup
  2540. for( asUINT n = 0; n < args.GetLength(); n++ )
  2541. if( args[n] )
  2542. {
  2543. asDELETE(args[n], asCExprContext);
  2544. }
  2545. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2546. if( namedArgs[n].ctx )
  2547. {
  2548. asDELETE(namedArgs[n].ctx, asCExprContext);
  2549. }
  2550. }
  2551. }
  2552. else if( node && node->nodeType == snInitList )
  2553. {
  2554. asCExprValue ti;
  2555. ti.Set(type);
  2556. ti.isVariable = (isVarGlobOrMem == 0);
  2557. ti.isTemporary = false;
  2558. ti.stackOffset = offset;
  2559. ti.isLValue = true;
  2560. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2561. }
  2562. else if( node && node->nodeType == snAssignment )
  2563. {
  2564. // Compile the expression
  2565. asCExprContext newExpr(engine);
  2566. asCExprContext* expr;
  2567. int r = 0;
  2568. if( preCompiled )
  2569. {
  2570. expr = preCompiled;
  2571. }
  2572. else
  2573. {
  2574. expr = &newExpr;
  2575. r = CompileAssignment(node, expr);
  2576. }
  2577. // handles initialized with null doesn't need any bytecode
  2578. // since handles will be initialized to null by default anyway
  2579. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2580. return false;
  2581. // Look for appropriate constructor
  2582. asCArray<int> funcs;
  2583. asCArray<asCExprContext *> args;
  2584. // Handles must use the handle assignment operation.
  2585. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2586. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2587. // Only do this if the expression is of the same type, as the expression is an assignment
  2588. // and an initialization constructor may not have the same meaning.
  2589. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2590. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2591. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2592. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2593. {
  2594. asSTypeBehaviour *beh = type.GetBehaviour();
  2595. if( beh )
  2596. {
  2597. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2598. funcs = beh->factories;
  2599. else
  2600. funcs = beh->constructors;
  2601. }
  2602. asCString str = type.Format(outFunc->nameSpace);
  2603. args.PushLast(expr);
  2604. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2605. // Make sure the argument is of the right type (and not just compatible with the expression)
  2606. if (funcs.GetLength() == 1)
  2607. {
  2608. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2609. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2610. funcs.PopLast();
  2611. }
  2612. }
  2613. if( funcs.GetLength() == 1 )
  2614. {
  2615. // Use the constructor
  2616. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2617. // Add the default values for arguments not explicitly supplied
  2618. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2619. if( r == asSUCCESS )
  2620. {
  2621. asCExprContext ctx(engine);
  2622. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2623. {
  2624. if( isVarGlobOrMem == 0 )
  2625. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2626. else
  2627. {
  2628. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2629. ctx.bc.Instr(asBC_RDSPtr);
  2630. if( isVarGlobOrMem == 1 )
  2631. {
  2632. // Store the returned handle in the global variable
  2633. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2634. }
  2635. else
  2636. {
  2637. // Store the returned handle in the member
  2638. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2639. ctx.bc.Instr(asBC_RDSPtr);
  2640. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2641. }
  2642. if( type.IsFuncdef() )
  2643. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2644. else
  2645. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2646. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2647. }
  2648. // Pop the reference left by the function call
  2649. ctx.bc.Instr(asBC_PopPtr);
  2650. }
  2651. else
  2652. {
  2653. bool onHeap = false;
  2654. if( isVarGlobOrMem == 0 )
  2655. {
  2656. // When the object is allocated on the heap, the address where the
  2657. // reference will be stored must be pushed on the stack before the
  2658. // arguments. This reference on the stack is safe, even if the script
  2659. // is suspended during the evaluation of the arguments.
  2660. onHeap = IsVariableOnHeap(offset);
  2661. if( onHeap )
  2662. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2663. }
  2664. else if( isVarGlobOrMem == 1 )
  2665. {
  2666. // Push the address of the location where the variable will be stored on the stack.
  2667. // This reference is safe, because the addresses of the global variables cannot change.
  2668. onHeap = true;
  2669. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2670. }
  2671. else
  2672. {
  2673. // Value types may be allocated inline if they are POD types
  2674. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2675. if( onHeap )
  2676. {
  2677. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2678. ctx.bc.Instr(asBC_RDSPtr);
  2679. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2680. }
  2681. }
  2682. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2683. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2684. // When the object is allocated on the stack, the address to the
  2685. // object is pushed on the stack after the arguments as the object pointer
  2686. if( !onHeap )
  2687. {
  2688. if( isVarGlobOrMem == 2 )
  2689. {
  2690. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2691. ctx.bc.Instr(asBC_RDSPtr);
  2692. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2693. }
  2694. else
  2695. {
  2696. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2697. }
  2698. }
  2699. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2700. if( isVarGlobOrMem == 0 )
  2701. {
  2702. // Mark the object in the local variable as initialized
  2703. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2704. }
  2705. }
  2706. ProcessDeferredParams(&ctx);
  2707. bc->AddCode(&ctx.bc);
  2708. }
  2709. }
  2710. else
  2711. {
  2712. // Call the default constructor, then call the assignment operator
  2713. asCExprContext ctx(engine);
  2714. // Call the default constructor here
  2715. if( isVarGlobOrMem == 0 )
  2716. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2717. else if( isVarGlobOrMem == 1 )
  2718. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2719. else if( isVarGlobOrMem == 2 )
  2720. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2721. if( r >= 0 )
  2722. {
  2723. if( type.IsPrimitive() )
  2724. {
  2725. if( type.IsReadOnly() && expr->type.isConstant )
  2726. {
  2727. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2728. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2729. isConstantExpression = true;
  2730. *constantValue = expr->type.GetConstantData();
  2731. }
  2732. asCExprContext lctx(engine);
  2733. if( isVarGlobOrMem == 0 )
  2734. lctx.type.SetVariable(type, offset, false);
  2735. else if( isVarGlobOrMem == 1 )
  2736. {
  2737. lctx.type.Set(type);
  2738. lctx.type.dataType.MakeReference(true);
  2739. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2740. // we skip this as the bytecode won't be used anyway, only the constant value
  2741. if( offset >= 0 )
  2742. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2743. }
  2744. else
  2745. {
  2746. asASSERT( isVarGlobOrMem == 2 );
  2747. lctx.type.Set(type);
  2748. lctx.type.dataType.MakeReference(true);
  2749. // Load the reference of the primitive member into the register
  2750. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2751. lctx.bc.Instr(asBC_RDSPtr);
  2752. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2753. lctx.bc.Instr(asBC_PopRPtr);
  2754. }
  2755. lctx.type.dataType.MakeReadOnly(false);
  2756. lctx.type.isLValue = true;
  2757. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2758. ProcessDeferredParams(&ctx);
  2759. }
  2760. else
  2761. {
  2762. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2763. // just the copy constructor. Only if no appropriate constructor is
  2764. // available should the assignment operator be used.
  2765. asCExprContext lexpr(engine);
  2766. lexpr.type.Set(type);
  2767. if( isVarGlobOrMem == 0 )
  2768. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2769. else if( isVarGlobOrMem == 1 )
  2770. lexpr.type.dataType.MakeReference(true);
  2771. else if( isVarGlobOrMem == 2 )
  2772. {
  2773. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2774. lexpr.type.dataType.MakeReference(true);
  2775. }
  2776. // Allow initialization of constant variables
  2777. lexpr.type.dataType.MakeReadOnly(false);
  2778. if( type.IsObjectHandle() )
  2779. lexpr.type.isExplicitHandle = true;
  2780. if( isVarGlobOrMem == 0 )
  2781. {
  2782. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2783. lexpr.type.stackOffset = (short)offset;
  2784. lexpr.type.isVariable = true;
  2785. }
  2786. else if( isVarGlobOrMem == 1 )
  2787. {
  2788. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2789. }
  2790. else
  2791. {
  2792. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2793. lexpr.bc.Instr(asBC_RDSPtr);
  2794. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2795. lexpr.type.stackOffset = -1;
  2796. }
  2797. lexpr.type.isLValue = true;
  2798. // If left expression resolves into a registered type
  2799. // check if the assignment operator is overloaded, and check
  2800. // the type of the right hand expression. If none is found
  2801. // the default action is a direct copy if it is the same type
  2802. // and a simple assignment.
  2803. bool assigned = false;
  2804. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2805. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2806. {
  2807. bool useHndlAssign = false;
  2808. if (lexpr.type.dataType.IsHandleToAsHandleType())
  2809. {
  2810. useHndlAssign = true;
  2811. // Make sure the right hand expression is treated as a handle
  2812. if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() )
  2813. {
  2814. // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
  2815. // Convert the expression to a handle
  2816. if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
  2817. {
  2818. asCDataType to = expr->type.dataType;
  2819. to.MakeHandle(true);
  2820. to.MakeReference(true);
  2821. to.MakeHandleToConst(expr->type.dataType.IsReadOnly());
  2822. ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false);
  2823. asASSERT(expr->type.dataType.IsObjectHandle());
  2824. }
  2825. else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
  2826. {
  2827. // For the ASHANDLE type we'll simply set the expression as a handle
  2828. expr->type.dataType.MakeHandle(true);
  2829. }
  2830. if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles())
  2831. {
  2832. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  2833. }
  2834. expr->type.isExplicitHandle = true;
  2835. }
  2836. }
  2837. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2838. if( assigned )
  2839. {
  2840. // Pop the resulting value
  2841. if( !ctx.type.dataType.IsPrimitive() )
  2842. ctx.bc.Instr(asBC_PopPtr);
  2843. // Release the argument
  2844. ProcessDeferredParams(&ctx);
  2845. // Release temporary variable that may be allocated by the overloaded operator
  2846. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2847. }
  2848. }
  2849. if( !assigned )
  2850. {
  2851. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2852. // If the expression is constant and the variable also is constant
  2853. // then mark the variable as pure constant. This will allow the compiler
  2854. // to optimize expressions with this variable.
  2855. if( type.IsReadOnly() && expr->type.isConstant )
  2856. {
  2857. isConstantExpression = true;
  2858. *constantValue = expr->type.GetConstantQW();
  2859. }
  2860. // Add expression code to bytecode
  2861. MergeExprBytecode(&ctx, expr);
  2862. // Add byte code for storing value of expression in variable
  2863. ctx.bc.AddCode(&lexpr.bc);
  2864. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2865. // Release temporary variables used by expression
  2866. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2867. ctx.bc.Instr(asBC_PopPtr);
  2868. ProcessDeferredParams(&ctx);
  2869. }
  2870. }
  2871. }
  2872. bc->AddCode(&ctx.bc);
  2873. }
  2874. }
  2875. else
  2876. {
  2877. asASSERT( node == 0 );
  2878. // Call the default constructor here, as no explicit initialization is done
  2879. if( isVarGlobOrMem == 0 )
  2880. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2881. else if( isVarGlobOrMem == 1 )
  2882. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2883. else if( isVarGlobOrMem == 2 )
  2884. {
  2885. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2886. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2887. else
  2888. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2889. }
  2890. }
  2891. return isConstantExpression;
  2892. }
  2893. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2894. {
  2895. // Check if the type supports initialization lists
  2896. if( var->dataType.GetTypeInfo() == 0 ||
  2897. var->dataType.GetBehaviour()->listFactory == 0 )
  2898. {
  2899. asCString str;
  2900. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2901. Error(str, node);
  2902. return;
  2903. }
  2904. // Construct the buffer with the elements
  2905. // Find the list factory
  2906. int funcId = var->dataType.GetBehaviour()->listFactory;
  2907. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2908. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2909. // for small buffers so that the dynamic allocation is skipped
  2910. // Create a new special object type for the lists. Both asCRestore and the
  2911. // context exception handler will need this to know how to parse the buffer.
  2912. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2913. // Allocate a temporary variable to hold the pointer to the buffer
  2914. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2915. asUINT bufferSize = 0;
  2916. // Evaluate all elements of the list
  2917. asCExprContext valueExpr(engine);
  2918. asCScriptNode *el = node;
  2919. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2920. int elementsInSubList = -1;
  2921. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2922. asASSERT( r || patternNode == 0 );
  2923. if (r < 0)
  2924. {
  2925. asCString msg;
  2926. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2927. Error(msg, node);
  2928. }
  2929. // After all values have been evaluated we know the final size of the buffer
  2930. asCExprContext allocExpr(engine);
  2931. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2932. // Merge the bytecode into the final sequence
  2933. bc->AddCode(&allocExpr.bc);
  2934. bc->AddCode(&valueExpr.bc);
  2935. // The object itself is the last to be created and will receive the pointer to the buffer
  2936. asCArray<asCExprContext *> args;
  2937. asCExprContext arg1(engine);
  2938. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2939. arg1.type.dataType.MakeReference(true);
  2940. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2941. args.PushLast(&arg1);
  2942. asCExprContext ctx(engine);
  2943. if( var->isVariable )
  2944. {
  2945. asASSERT( isVarGlobOrMem == 0 );
  2946. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2947. {
  2948. ctx.bc.AddCode(&arg1.bc);
  2949. // Call factory and store the handle in the given variable
  2950. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2951. ctx.bc.Instr(asBC_PopPtr);
  2952. }
  2953. else
  2954. {
  2955. // Call the constructor
  2956. // When the object is allocated on the heap, the address where the
  2957. // reference will be stored must be pushed on the stack before the
  2958. // arguments. This reference on the stack is safe, even if the script
  2959. // is suspended during the evaluation of the arguments.
  2960. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2961. if( onHeap )
  2962. ctx.bc.InstrSHORT(asBC_PSF, (short)var->stackOffset);
  2963. ctx.bc.AddCode(&arg1.bc);
  2964. // When the object is allocated on the stack, the address to the
  2965. // object is pushed on the stack after the arguments as the object pointer
  2966. if( !onHeap )
  2967. ctx.bc.InstrSHORT(asBC_PSF, (short)var->stackOffset);
  2968. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2969. // Mark the object in the local variable as initialized
  2970. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2971. }
  2972. }
  2973. else
  2974. {
  2975. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2976. {
  2977. ctx.bc.AddCode(&arg1.bc);
  2978. PerformFunctionCall(funcId, &ctx, false, &args);
  2979. ctx.bc.Instr(asBC_RDSPtr);
  2980. if( isVarGlobOrMem == 1 )
  2981. {
  2982. // Store the returned handle in the global variable
  2983. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2984. }
  2985. else
  2986. {
  2987. // Store the returned handle in the member
  2988. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2989. ctx.bc.Instr(asBC_RDSPtr);
  2990. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2991. }
  2992. if (var->dataType.IsFuncdef())
  2993. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2994. else
  2995. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2996. ctx.bc.Instr(asBC_PopPtr);
  2997. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2998. }
  2999. else
  3000. {
  3001. bool onHeap = true;
  3002. // Put the address where the object pointer will be placed on the stack
  3003. if( isVarGlobOrMem == 1 )
  3004. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  3005. else
  3006. {
  3007. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  3008. if( onHeap )
  3009. {
  3010. ctx.bc.InstrSHORT(asBC_PSF, 0);
  3011. ctx.bc.Instr(asBC_RDSPtr);
  3012. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  3013. }
  3014. }
  3015. // Add the address of the list buffer as the argument
  3016. ctx.bc.AddCode(&arg1.bc);
  3017. if( !onHeap )
  3018. {
  3019. ctx.bc.InstrSHORT(asBC_PSF, 0);
  3020. ctx.bc.Instr(asBC_RDSPtr);
  3021. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  3022. }
  3023. // Call the ALLOC instruction to allocate memory and invoke constructor
  3024. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  3025. }
  3026. }
  3027. bc->AddCode(&ctx.bc);
  3028. // Free the temporary buffer. The FREE instruction will make sure to destroy
  3029. // each element in the buffer so there is no need to do this manually
  3030. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  3031. ReleaseTemporaryVariable(bufferVar, bc);
  3032. }
  3033. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  3034. {
  3035. if( patternNode->type == asLPT_START )
  3036. {
  3037. if( valueNode == 0 || valueNode->nodeType != snInitList )
  3038. {
  3039. Error(TXT_EXPECTED_LIST, valueNode);
  3040. return -1;
  3041. }
  3042. // Compile all values until asLPT_END
  3043. patternNode = patternNode->next;
  3044. asCScriptNode *node = valueNode->firstChild;
  3045. while( patternNode->type != asLPT_END )
  3046. {
  3047. // Check for missing value here, else the error reporting will not have a source position to report the error for
  3048. if( node == 0 && patternNode->type == asLPT_TYPE )
  3049. {
  3050. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  3051. return -1;
  3052. }
  3053. asCScriptNode *errNode = node;
  3054. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  3055. if( r < 0 ) return r;
  3056. if( r == 1 )
  3057. {
  3058. asASSERT( engine->ep.disallowEmptyListElements );
  3059. // Empty elements in the middle are not allowed
  3060. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3061. }
  3062. asASSERT( patternNode );
  3063. }
  3064. if( node )
  3065. {
  3066. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  3067. return -1;
  3068. }
  3069. // Move to the next node
  3070. valueNode = valueNode->next;
  3071. patternNode = patternNode->next;
  3072. }
  3073. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  3074. {
  3075. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  3076. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  3077. asEListPatternNodeType repeatType = patternNode->type;
  3078. asCScriptNode *firstValue = valueNode;
  3079. // The following values will be repeated N times
  3080. patternNode = patternNode->next;
  3081. // Keep track of the patternNode so it can be reset
  3082. asSListPatternNode *nextNode = patternNode;
  3083. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  3084. if( bufferSize & 0x3 )
  3085. bufferSize += 4 - (bufferSize & 0x3);
  3086. // The first dword will hold the number of elements in the list
  3087. asDWORD currSize = bufferSize;
  3088. bufferSize += 4;
  3089. asUINT countElements = 0;
  3090. int elementsInSubSubList = -1;
  3091. asCExprContext ctx(engine);
  3092. while( valueNode )
  3093. {
  3094. patternNode = nextNode;
  3095. asCScriptNode *errNode = valueNode;
  3096. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  3097. if( r < 0 ) return r;
  3098. if( r == 0 )
  3099. countElements++;
  3100. else
  3101. {
  3102. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  3103. if( valueNode )
  3104. {
  3105. // Empty elements in the middle are not allowed
  3106. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3107. }
  3108. }
  3109. }
  3110. if( countElements == 0 )
  3111. {
  3112. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  3113. patternNode = nextNode;
  3114. if( patternNode->type == asLPT_TYPE )
  3115. patternNode = patternNode->next;
  3116. else if( patternNode->type == asLPT_START )
  3117. {
  3118. int subCount = 1;
  3119. do
  3120. {
  3121. patternNode = patternNode->next;
  3122. if( patternNode->type == asLPT_START )
  3123. subCount++;
  3124. else if( patternNode->type == asLPT_END )
  3125. subCount--;
  3126. } while( subCount > 0 );
  3127. patternNode = patternNode->next;
  3128. }
  3129. }
  3130. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  3131. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  3132. {
  3133. if( countElements < asUINT(elementsInSubList) )
  3134. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  3135. else
  3136. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  3137. return -1;
  3138. }
  3139. else
  3140. {
  3141. // Return to caller the amount of elments in this sublist
  3142. elementsInSubList = countElements;
  3143. }
  3144. // The first dword in the buffer will hold the number of elements
  3145. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  3146. // Add the values
  3147. bcInit.AddCode(&ctx.bc);
  3148. }
  3149. else if( patternNode->type == asLPT_TYPE )
  3150. {
  3151. bool isEmpty = false;
  3152. // Determine the size of the element
  3153. asUINT size = 0;
  3154. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  3155. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  3156. {
  3157. asCExprContext lctx(engine);
  3158. asCExprContext rctx(engine);
  3159. if( valueNode->nodeType == snAssignment )
  3160. {
  3161. // Compile the assignment expression
  3162. CompileAssignment(valueNode, &rctx);
  3163. if( dt.GetTokenType() == ttQuestion )
  3164. {
  3165. // Make sure the type is not ambiguous
  3166. DetermineSingleFunc(&rctx, valueNode);
  3167. // We now know the type
  3168. dt = rctx.type.dataType;
  3169. dt.MakeReadOnly(false);
  3170. dt.MakeReference(false);
  3171. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3172. if( bufferSize & 0x3 )
  3173. bufferSize += 4 - (bufferSize & 0x3);
  3174. // When value assignment for reference types us disabled, make sure all ref types are passed in as handles
  3175. if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles())
  3176. dt.MakeHandle(true);
  3177. // Place the type id in the buffer
  3178. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3179. bufferSize += 4;
  3180. }
  3181. }
  3182. else if( valueNode->nodeType == snInitList )
  3183. {
  3184. if( dt.GetTokenType() == ttQuestion )
  3185. {
  3186. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3187. asCString str;
  3188. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3189. Error(str.AddressOf(), valueNode);
  3190. rctx.type.SetDummy();
  3191. dt = rctx.type.dataType;
  3192. }
  3193. else
  3194. {
  3195. // Allocate a temporary variable that will be initialized with the list
  3196. int offset = AllocateVariable(dt, true);
  3197. rctx.type.Set(dt);
  3198. rctx.type.isVariable = true;
  3199. rctx.type.isTemporary = true;
  3200. rctx.type.stackOffset = offset;
  3201. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3202. // Put the object on the stack
  3203. rctx.bc.InstrSHORT(asBC_PSF, (short)rctx.type.stackOffset);
  3204. // It is a reference that we place on the stack
  3205. rctx.type.dataType.MakeReference(true);
  3206. }
  3207. }
  3208. // Determine size of the element
  3209. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3210. size = dt.GetSizeInMemoryBytes();
  3211. else
  3212. size = AS_PTR_SIZE*4;
  3213. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3214. if( size >= 4 && (bufferSize & 0x3) )
  3215. bufferSize += 4 - (bufferSize & 0x3);
  3216. // Compile the lvalue
  3217. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3218. lctx.type.Set(dt);
  3219. lctx.type.isLValue = true;
  3220. if( dt.IsPrimitive() )
  3221. {
  3222. lctx.bc.Instr(asBC_PopRPtr);
  3223. lctx.type.dataType.MakeReference(true);
  3224. }
  3225. else if( dt.IsObjectHandle() ||
  3226. dt.GetTypeInfo()->flags & asOBJ_REF )
  3227. {
  3228. lctx.type.isExplicitHandle = true;
  3229. lctx.type.dataType.MakeReference(true);
  3230. }
  3231. else
  3232. {
  3233. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3234. // Make sure the object has been constructed before the assignment
  3235. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3236. asSTypeBehaviour *beh = dt.GetBehaviour();
  3237. int func = 0;
  3238. if( beh ) func = beh->construct;
  3239. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3240. {
  3241. asCString str;
  3242. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3243. Error(str, valueNode);
  3244. }
  3245. else if( func )
  3246. {
  3247. // Call the constructor as a normal function
  3248. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3249. asCExprContext ctx(engine);
  3250. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3251. bcInit.AddCode(&ctx.bc);
  3252. }
  3253. }
  3254. if( lctx.type.dataType.IsNullHandle() )
  3255. {
  3256. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3257. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3258. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3259. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3260. }
  3261. else
  3262. {
  3263. asCExprContext ctx(engine);
  3264. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3265. if( !ctx.type.dataType.IsPrimitive() )
  3266. ctx.bc.Instr(asBC_PopPtr);
  3267. // Release temporary variables used by expression
  3268. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3269. ProcessDeferredParams(&ctx);
  3270. bcInit.AddCode(&ctx.bc);
  3271. }
  3272. }
  3273. else
  3274. {
  3275. if( builder->engine->ep.disallowEmptyListElements )
  3276. {
  3277. // Empty elements are not allowed, except if it is the last in the list
  3278. isEmpty = true;
  3279. }
  3280. else
  3281. {
  3282. // There is no specific value so we need to fill it with a default value
  3283. if( dt.GetTokenType() == ttQuestion )
  3284. {
  3285. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3286. if( bufferSize & 0x3 )
  3287. bufferSize += 4 - (bufferSize & 0x3);
  3288. // Place the type id for a null handle in the buffer
  3289. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3290. bufferSize += 4;
  3291. dt = asCDataType::CreateNullHandle();
  3292. // No need to initialize the handle as the buffer is already initialized with zeroes
  3293. }
  3294. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3295. {
  3296. // For value types with default constructor we need to call the constructor
  3297. asSTypeBehaviour *beh = dt.GetBehaviour();
  3298. int func = 0;
  3299. if( beh ) func = beh->construct;
  3300. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3301. {
  3302. asCString str;
  3303. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3304. Error(str, valueNode);
  3305. }
  3306. else if( func )
  3307. {
  3308. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3309. if( bufferSize & 0x3 )
  3310. bufferSize += 4 - (bufferSize & 0x3);
  3311. // Call the constructor as a normal function
  3312. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3313. asCExprContext ctx(engine);
  3314. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3315. bcInit.AddCode(&ctx.bc);
  3316. }
  3317. }
  3318. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3319. {
  3320. // For ref types (not handles) we need to call the default factory
  3321. asSTypeBehaviour *beh = dt.GetBehaviour();
  3322. int func = 0;
  3323. if( beh ) func = beh->factory;
  3324. if( func == 0 )
  3325. {
  3326. asCString str;
  3327. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3328. Error(str, valueNode);
  3329. }
  3330. else if( func )
  3331. {
  3332. asCExprContext rctx(engine);
  3333. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3334. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3335. if( bufferSize & 0x3 )
  3336. bufferSize += 4 - (bufferSize & 0x3);
  3337. asCExprContext lctx(engine);
  3338. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3339. lctx.type.Set(dt);
  3340. lctx.type.isLValue = true;
  3341. lctx.type.isExplicitHandle = true;
  3342. lctx.type.dataType.MakeReference(true);
  3343. asCExprContext ctx(engine);
  3344. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3345. if( !ctx.type.dataType.IsPrimitive() )
  3346. ctx.bc.Instr(asBC_PopPtr);
  3347. // Release temporary variables used by expression
  3348. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3349. ProcessDeferredParams(&ctx);
  3350. bcInit.AddCode(&ctx.bc);
  3351. }
  3352. }
  3353. }
  3354. }
  3355. if( !isEmpty )
  3356. {
  3357. // Determine size of the element
  3358. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3359. size = dt.GetSizeInMemoryBytes();
  3360. else
  3361. size = AS_PTR_SIZE*4;
  3362. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3363. bufferSize += size;
  3364. }
  3365. // Move to the next element
  3366. patternNode = patternNode->next;
  3367. valueNode = valueNode->next;
  3368. if( isEmpty )
  3369. {
  3370. // The caller will determine if the empty element should be ignored or not
  3371. return 1;
  3372. }
  3373. }
  3374. else
  3375. asASSERT( false );
  3376. return 0;
  3377. }
  3378. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3379. {
  3380. // Don't clear the hasReturn flag if this is an empty statement
  3381. // to avoid false errors of 'not all paths return'
  3382. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3383. *hasReturn = false;
  3384. if (statement->nodeType == snStatementBlock)
  3385. CompileStatementBlock(statement, true, hasReturn, bc);
  3386. else if (statement->nodeType == snIf)
  3387. CompileIfStatement(statement, hasReturn, bc);
  3388. else if (statement->nodeType == snFor)
  3389. CompileForStatement(statement, bc);
  3390. else if (statement->nodeType == snWhile)
  3391. CompileWhileStatement(statement, bc);
  3392. else if (statement->nodeType == snDoWhile)
  3393. CompileDoWhileStatement(statement, bc);
  3394. else if (statement->nodeType == snExpressionStatement)
  3395. CompileExpressionStatement(statement, bc);
  3396. else if (statement->nodeType == snBreak)
  3397. CompileBreakStatement(statement, bc);
  3398. else if (statement->nodeType == snContinue)
  3399. CompileContinueStatement(statement, bc);
  3400. else if (statement->nodeType == snSwitch)
  3401. CompileSwitchStatement(statement, hasReturn, bc);
  3402. else if (statement->nodeType == snTryCatch)
  3403. CompileTryCatch(statement, hasReturn, bc);
  3404. else if (statement->nodeType == snReturn)
  3405. {
  3406. CompileReturnStatement(statement, bc);
  3407. *hasReturn = true;
  3408. }
  3409. else
  3410. asASSERT(false);
  3411. }
  3412. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *hasReturn, asCByteCode *bc)
  3413. {
  3414. *hasReturn = false;
  3415. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3416. // Reserve label for break statements
  3417. int breakLabel = nextLabel++;
  3418. breakLabels.PushLast(breakLabel);
  3419. // Add a variable scope that will be used by CompileBreak
  3420. // to know where to stop deallocating variables
  3421. AddVariableScope(true, false);
  3422. //---------------------------
  3423. // Compile the switch expression
  3424. //-------------------------------
  3425. // Compile the switch expression
  3426. asCExprContext expr(engine);
  3427. CompileAssignment(snode->firstChild, &expr);
  3428. // Verify that the expression is a primitive type
  3429. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3430. {
  3431. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3432. return;
  3433. }
  3434. if( ProcessPropertyGetAccessor(&expr, snode) < 0 )
  3435. return;
  3436. // TODO: Need to support 64bit integers
  3437. // Convert the expression to a 32bit variable
  3438. asCDataType to;
  3439. if( expr.type.dataType.IsIntegerType() )
  3440. to.SetTokenType(ttInt);
  3441. else if( expr.type.dataType.IsUnsignedType() )
  3442. to.SetTokenType(ttUInt);
  3443. // Make sure the value is in a variable
  3444. if( expr.type.dataType.IsReference() )
  3445. ConvertToVariable(&expr);
  3446. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3447. ConvertToVariable(&expr);
  3448. int offset = expr.type.stackOffset;
  3449. ProcessDeferredParams(&expr);
  3450. //-------------------------------
  3451. // Determine case values and labels
  3452. //--------------------------------
  3453. // Remember the first label so that we can later pass the
  3454. // correct label to each CompileCase()
  3455. int firstCaseLabel = nextLabel;
  3456. int defaultLabel = 0;
  3457. asCArray<int> caseValues;
  3458. asCArray<int> caseLabels;
  3459. // Compile all case comparisons and make them jump to the right label
  3460. asCScriptNode *cnode = snode->firstChild->next;
  3461. while( cnode )
  3462. {
  3463. // Each case should have a constant expression
  3464. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3465. {
  3466. // Compile expression
  3467. asCExprContext c(engine);
  3468. CompileExpression(cnode->firstChild, &c);
  3469. // Verify that the result is a constant
  3470. if( !c.type.isConstant )
  3471. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3472. // Verify that the result is an integral number
  3473. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3474. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3475. else
  3476. {
  3477. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3478. // Has this case been declared already?
  3479. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3480. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3481. // TODO: Optimize: We can insert the numbers sorted already
  3482. // Store constant for later use
  3483. caseValues.PushLast(c.type.GetConstantDW());
  3484. // Reserve label for this case
  3485. caseLabels.PushLast(nextLabel++);
  3486. }
  3487. }
  3488. else
  3489. {
  3490. // TODO: It shouldn't be necessary for the default case to be the last one.
  3491. // Is default the last case?
  3492. if( cnode->next )
  3493. {
  3494. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3495. break;
  3496. }
  3497. // Reserve label for this case
  3498. defaultLabel = nextLabel++;
  3499. }
  3500. cnode = cnode->next;
  3501. }
  3502. // check for empty switch
  3503. if (caseValues.GetLength() == 0)
  3504. {
  3505. Error(TXT_EMPTY_SWITCH, snode);
  3506. return;
  3507. }
  3508. if( defaultLabel == 0 )
  3509. defaultLabel = breakLabel;
  3510. //---------------------------------
  3511. // Output the optimized case comparisons
  3512. // with jumps to the case code
  3513. //------------------------------------
  3514. // Sort the case values by increasing value. Do the sort together with the labels
  3515. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3516. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3517. {
  3518. for( int bck = fwd - 1; bck >= 0; bck-- )
  3519. {
  3520. int bckp = bck + 1;
  3521. if( caseValues[bck] > caseValues[bckp] )
  3522. {
  3523. // Swap the values in both arrays
  3524. int swap = caseValues[bckp];
  3525. caseValues[bckp] = caseValues[bck];
  3526. caseValues[bck] = swap;
  3527. swap = caseLabels[bckp];
  3528. caseLabels[bckp] = caseLabels[bck];
  3529. caseLabels[bck] = swap;
  3530. }
  3531. else
  3532. break;
  3533. }
  3534. }
  3535. // Find ranges of consecutive numbers
  3536. asCArray<int> ranges;
  3537. ranges.PushLast(0);
  3538. asUINT n;
  3539. for( n = 1; n < caseValues.GetLength(); ++n )
  3540. {
  3541. // We can join numbers that are less than 5 numbers
  3542. // apart since the output code will still be smaller
  3543. if( caseValues[n] > caseValues[n-1] + 5 )
  3544. ranges.PushLast(n);
  3545. }
  3546. // If the value is larger than the largest case value, jump to default
  3547. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3548. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3549. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3550. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3551. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3552. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3553. // binary search instead of a linear search through the ranges
  3554. // For each range
  3555. int range;
  3556. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3557. {
  3558. // Find the largest value in this range
  3559. int maxRange = caseValues[ranges[range]];
  3560. int index = ranges[range];
  3561. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3562. maxRange = caseValues[index];
  3563. // If there are only 2 numbers then it is better to compare them directly
  3564. if( index - ranges[range] > 2 )
  3565. {
  3566. // If the value is smaller than the smallest case value in the range, jump to default
  3567. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3568. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3569. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3570. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3571. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3572. int nextRangeLabel = nextLabel++;
  3573. // If this is the last range we don't have to make this test
  3574. if( range < (int)ranges.GetLength() - 1 )
  3575. {
  3576. // If the value is larger than the largest case value in the range, jump to the next range
  3577. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3578. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3579. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3580. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3581. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3582. }
  3583. // Jump forward according to the value
  3584. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3585. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3586. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3587. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3588. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3589. // Add the list of jumps to the correct labels (any holes, jump to default)
  3590. index = ranges[range];
  3591. for( int i = caseValues[index]; i <= maxRange; i++ )
  3592. {
  3593. if( caseValues[index] == i )
  3594. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3595. else
  3596. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3597. }
  3598. expr.bc.Label((short)nextRangeLabel);
  3599. }
  3600. else
  3601. {
  3602. // Simply make a comparison with each value
  3603. for( int i = ranges[range]; i < index; ++i )
  3604. {
  3605. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3606. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3607. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3608. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3609. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3610. }
  3611. }
  3612. }
  3613. // Catch any value that falls trough
  3614. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3615. // Release the temporary variable previously stored
  3616. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3617. // TODO: optimize: Should optimize each piece individually
  3618. expr.bc.OptimizeLocally(tempVariableOffsets);
  3619. //----------------------------------
  3620. // Output case implementations
  3621. //----------------------------------
  3622. // Switch cases must be able to report if all paths have return too
  3623. // If the switch case has no default case, then it doesn't return
  3624. // If a case has a break without first return then the switch has no return
  3625. // If a case doesn't have a return, but falls through to a case that does return then the case can be said to have a return too
  3626. *hasReturn = true;
  3627. // Compile case implementations, each one with the label before it
  3628. cnode = snode->firstChild->next;
  3629. while( cnode )
  3630. {
  3631. // Each case should have a constant expression
  3632. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3633. {
  3634. expr.bc.Label((short)firstCaseLabel++);
  3635. bool caseHasReturn, caseHasBreak;
  3636. CompileCase(cnode->firstChild->next, &expr.bc, &caseHasReturn, &caseHasBreak);
  3637. // If the case does not return and have a break, then we know the switch doesn't return in all paths
  3638. if (!caseHasReturn && caseHasBreak)
  3639. *hasReturn = false;
  3640. }
  3641. else
  3642. {
  3643. expr.bc.Label((short)defaultLabel);
  3644. // Is default the last case?
  3645. if( cnode->next )
  3646. {
  3647. // We've already reported this error
  3648. break;
  3649. }
  3650. bool caseHasReturn, caseHasBreak;
  3651. CompileCase(cnode->firstChild, &expr.bc, &caseHasReturn, &caseHasBreak);
  3652. // If the default case does not return then we know the switch doesn't return in all paths
  3653. if (!caseHasReturn)
  3654. *hasReturn = false;
  3655. }
  3656. cnode = cnode->next;
  3657. }
  3658. // If there is no default case, then the switch cannot be said to return in all paths
  3659. if (defaultLabel == breakLabel)
  3660. *hasReturn = false;
  3661. //--------------------------------
  3662. bc->AddCode(&expr.bc);
  3663. // Add break label
  3664. bc->Label((short)breakLabel);
  3665. breakLabels.PopLast();
  3666. RemoveVariableScope();
  3667. }
  3668. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc, bool *hasReturn, bool *hasBreak)
  3669. {
  3670. *hasBreak = false;
  3671. *hasReturn = false;
  3672. bool hasUnreachableCode = false;
  3673. while( node )
  3674. {
  3675. if( !hasUnreachableCode && (*hasReturn || *hasBreak) )
  3676. {
  3677. hasUnreachableCode = true;
  3678. Warning(TXT_UNREACHABLE_CODE, node);
  3679. break;
  3680. }
  3681. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3682. *hasBreak = true;
  3683. asCByteCode statement(engine);
  3684. if( node->nodeType == snDeclaration )
  3685. {
  3686. Error(TXT_DECL_IN_SWITCH, node);
  3687. // Compile it anyway to avoid further compiler errors
  3688. CompileDeclaration(node, &statement);
  3689. }
  3690. else
  3691. CompileStatement(node, hasReturn, &statement);
  3692. LineInstr(bc, node->tokenPos);
  3693. bc->AddCode(&statement);
  3694. if( !hasCompileErrors )
  3695. asASSERT( tempVariables.GetLength() == 0 );
  3696. node = node->next;
  3697. }
  3698. }
  3699. void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc)
  3700. {
  3701. // We will use one label before and another after the catch statement
  3702. int beforeCatchLabel = nextLabel++;
  3703. int afterCatchLabel = nextLabel++;
  3704. // Compile the try block
  3705. bool hasReturnTry;
  3706. asCByteCode tryBC(engine);
  3707. CompileStatement(node->firstChild, &hasReturnTry, &tryBC);
  3708. // Add marker to unwind exception until here, then jump to catch block
  3709. bc->TryBlock((short)beforeCatchLabel);
  3710. // Add the byte code
  3711. LineInstr(bc, node->firstChild->tokenPos);
  3712. bc->AddCode(&tryBC);
  3713. // Add jump to after catch
  3714. bc->InstrINT(asBC_JMP, afterCatchLabel);
  3715. // Compile the catch block
  3716. bool hasReturnCatch;
  3717. asCByteCode catchBC(engine);
  3718. CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC);
  3719. // Add marker to tell bytecode optimizer that this is a catch
  3720. // block so the code is not removed as unreachable code
  3721. bc->Label((short)beforeCatchLabel);
  3722. // Add the byte code
  3723. LineInstr(bc, node->firstChild->next->tokenPos);
  3724. bc->AddCode(&catchBC);
  3725. // Add the label after catch
  3726. bc->Label((short)afterCatchLabel);
  3727. // The try/catch statement only has return (i.e. no code after
  3728. // the try/catch block will be executed) if both blocks have
  3729. *hasReturn = hasReturnTry && hasReturnCatch;
  3730. }
  3731. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3732. {
  3733. // We will use one label for the if statement
  3734. // and possibly another for the else statement
  3735. int afterLabel = nextLabel++;
  3736. // Compile the expression
  3737. asCExprContext expr(engine);
  3738. int r = CompileAssignment(inode->firstChild, &expr);
  3739. if( r == 0 )
  3740. {
  3741. // Allow value types to be converted to bool using 'bool opImplConv()'
  3742. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3743. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3744. if (!expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)))
  3745. {
  3746. asCString str;
  3747. str.Format(TXT_EXPR_MUST_BE_BOOL_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf());
  3748. Error(str, inode->firstChild);
  3749. }
  3750. else
  3751. {
  3752. if( !expr.type.isConstant )
  3753. {
  3754. if( ProcessPropertyGetAccessor(&expr, inode) < 0 )
  3755. return;
  3756. ConvertToVariable(&expr);
  3757. ProcessDeferredParams(&expr);
  3758. // Add a test
  3759. expr.bc.InstrSHORT(asBC_CpyVtoR4, (short)expr.type.stackOffset);
  3760. expr.bc.Instr(asBC_ClrHi);
  3761. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3762. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3763. expr.bc.OptimizeLocally(tempVariableOffsets);
  3764. bc->AddCode(&expr.bc);
  3765. }
  3766. #if AS_SIZEOF_BOOL == 1
  3767. else if( expr.type.GetConstantB() == 0 )
  3768. #else
  3769. else if (expr.type.GetConstantDW() == 0)
  3770. #endif
  3771. {
  3772. // Jump to the else case
  3773. bc->InstrINT(asBC_JMP, afterLabel);
  3774. // TODO: Should we warn that the expression will always go to the else?
  3775. }
  3776. }
  3777. }
  3778. // Compile the if statement
  3779. bool origIsConstructorCalled = m_isConstructorCalled;
  3780. bool hasReturn1;
  3781. asCByteCode ifBC(engine);
  3782. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3783. // Add the byte code
  3784. LineInstr(bc, inode->firstChild->next->tokenPos);
  3785. bc->AddCode(&ifBC);
  3786. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3787. {
  3788. // Don't allow if( expr );
  3789. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3790. }
  3791. // If one of the statements call the constructor, the other must as well
  3792. // otherwise it is possible the constructor is never called
  3793. bool constructorCall1 = false;
  3794. bool constructorCall2 = false;
  3795. if( !origIsConstructorCalled && m_isConstructorCalled )
  3796. constructorCall1 = true;
  3797. // Do we have an else statement?
  3798. if( inode->firstChild->next != inode->lastChild )
  3799. {
  3800. // Reset the constructor called flag so the else statement can call the constructor too
  3801. m_isConstructorCalled = origIsConstructorCalled;
  3802. int afterElse = 0;
  3803. if( !hasReturn1 )
  3804. {
  3805. afterElse = nextLabel++;
  3806. // Add jump to after the else statement
  3807. bc->InstrINT(asBC_JMP, afterElse);
  3808. }
  3809. // Add label for the else statement
  3810. bc->Label((short)afterLabel);
  3811. bool hasReturn2;
  3812. asCByteCode elseBC(engine);
  3813. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3814. // Add byte code for the else statement
  3815. LineInstr(bc, inode->lastChild->tokenPos);
  3816. bc->AddCode(&elseBC);
  3817. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3818. {
  3819. // Don't allow if( expr ) {} else;
  3820. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3821. }
  3822. if( !hasReturn1 )
  3823. {
  3824. // Add label for the end of else statement
  3825. bc->Label((short)afterElse);
  3826. }
  3827. // The if statement only has return if both alternatives have
  3828. *hasReturn = hasReturn1 && hasReturn2;
  3829. if( !origIsConstructorCalled && m_isConstructorCalled )
  3830. constructorCall2 = true;
  3831. }
  3832. else
  3833. {
  3834. // Add label for the end of if statement
  3835. bc->Label((short)afterLabel);
  3836. *hasReturn = false;
  3837. }
  3838. // Make sure both or neither conditions call a constructor
  3839. if( (constructorCall1 && !constructorCall2) ||
  3840. (constructorCall2 && !constructorCall1) )
  3841. {
  3842. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3843. }
  3844. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3845. }
  3846. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3847. {
  3848. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3849. AddVariableScope(true, true);
  3850. // We will use three labels for the for loop
  3851. int conditionLabel = nextLabel++;
  3852. int afterLabel = nextLabel++;
  3853. int continueLabel = nextLabel++;
  3854. int insideLabel = nextLabel++;
  3855. continueLabels.PushLast(continueLabel);
  3856. breakLabels.PushLast(afterLabel);
  3857. //---------------------------------------
  3858. // Compile the initialization statement
  3859. asCByteCode initBC(engine);
  3860. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3861. if( fnode->firstChild->nodeType == snDeclaration )
  3862. CompileDeclaration(fnode->firstChild, &initBC);
  3863. else
  3864. CompileExpressionStatement(fnode->firstChild, &initBC);
  3865. //-----------------------------------
  3866. // Compile the condition statement
  3867. asCExprContext expr(engine);
  3868. asCScriptNode *second = fnode->firstChild->next;
  3869. if( second->firstChild )
  3870. {
  3871. int r = CompileAssignment(second->firstChild, &expr);
  3872. if( r >= 0 )
  3873. {
  3874. // Allow value types to be converted to bool using 'bool opImplConv()'
  3875. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3876. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3877. if (!expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)))
  3878. {
  3879. asCString str;
  3880. str.Format(TXT_EXPR_MUST_BE_BOOL_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf());
  3881. Error(str, second);
  3882. }
  3883. else
  3884. {
  3885. if( ProcessPropertyGetAccessor(&expr, second) < 0 )
  3886. return;
  3887. ConvertToVariable(&expr);
  3888. ProcessDeferredParams(&expr);
  3889. // If expression is false exit the loop
  3890. expr.bc.InstrSHORT(asBC_CpyVtoR4, (short)expr.type.stackOffset);
  3891. expr.bc.Instr(asBC_ClrHi);
  3892. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3893. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3894. expr.bc.OptimizeLocally(tempVariableOffsets);
  3895. // Prepend the line instruction for the condition
  3896. asCByteCode tmp(engine);
  3897. LineInstr(&tmp, second->firstChild->tokenPos);
  3898. tmp.AddCode(&expr.bc);
  3899. expr.bc.AddCode(&tmp);
  3900. }
  3901. }
  3902. }
  3903. //---------------------------
  3904. // Compile the increment statement(s)
  3905. asCByteCode nextBC(engine);
  3906. asCScriptNode *cnode = second->next;
  3907. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3908. {
  3909. LineInstr(&nextBC, cnode->tokenPos);
  3910. CompileExpressionStatement(cnode, &nextBC);
  3911. cnode = cnode->next;
  3912. }
  3913. //------------------------------
  3914. // Compile loop statement
  3915. bool hasReturn;
  3916. asCByteCode forBC(engine);
  3917. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3918. //-------------------------------
  3919. // Join the code pieces
  3920. bc->AddCode(&initBC);
  3921. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3922. bc->Label((short)insideLabel);
  3923. // Add a suspend bytecode inside the loop to guarantee
  3924. // that the application can suspend the execution
  3925. bc->Instr(asBC_SUSPEND);
  3926. bc->InstrPTR(asBC_JitEntry, 0);
  3927. LineInstr(bc, fnode->lastChild->tokenPos);
  3928. bc->AddCode(&forBC);
  3929. bc->Label((short)continueLabel);
  3930. bc->AddCode(&nextBC);
  3931. bc->Label((short)conditionLabel);
  3932. if( expr.bc.GetLastInstr() == -1 )
  3933. // There is no condition, so we just always jump
  3934. bc->InstrDWORD(asBC_JMP, insideLabel);
  3935. else
  3936. bc->AddCode(&expr.bc);
  3937. bc->Label((short)afterLabel);
  3938. continueLabels.PopLast();
  3939. breakLabels.PopLast();
  3940. // Deallocate variables in this block, in reverse order
  3941. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3942. {
  3943. sVariable *v = variables->variables[n];
  3944. // Call variable destructors here, for variables not yet destroyed
  3945. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3946. // Don't deallocate function parameters
  3947. if( v->stackOffset > 0 )
  3948. DeallocateVariable(v->stackOffset);
  3949. }
  3950. RemoveVariableScope();
  3951. }
  3952. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3953. {
  3954. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3955. AddVariableScope(true, true);
  3956. // We will use two labels for the while loop
  3957. int beforeLabel = nextLabel++;
  3958. int afterLabel = nextLabel++;
  3959. continueLabels.PushLast(beforeLabel);
  3960. breakLabels.PushLast(afterLabel);
  3961. // Add label before the expression
  3962. bc->Label((short)beforeLabel);
  3963. // Compile expression
  3964. asCExprContext expr(engine);
  3965. int r = CompileAssignment(wnode->firstChild, &expr);
  3966. if( r == 0 )
  3967. {
  3968. // Allow value types to be converted to bool using 'bool opImplConv()'
  3969. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3970. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3971. if (!expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)))
  3972. {
  3973. asCString str;
  3974. str.Format(TXT_EXPR_MUST_BE_BOOL_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf());
  3975. Error(str, wnode->firstChild);
  3976. }
  3977. else
  3978. {
  3979. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  3980. return;
  3981. ConvertToVariable(&expr);
  3982. ProcessDeferredParams(&expr);
  3983. // Jump to end of statement if expression is false
  3984. expr.bc.InstrSHORT(asBC_CpyVtoR4, (short)expr.type.stackOffset);
  3985. expr.bc.Instr(asBC_ClrHi);
  3986. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3987. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3988. expr.bc.OptimizeLocally(tempVariableOffsets);
  3989. bc->AddCode(&expr.bc);
  3990. }
  3991. }
  3992. // Add a suspend bytecode inside the loop to guarantee
  3993. // that the application can suspend the execution
  3994. bc->Instr(asBC_SUSPEND);
  3995. bc->InstrPTR(asBC_JitEntry, 0);
  3996. // Compile statement
  3997. bool hasReturn;
  3998. asCByteCode whileBC(engine);
  3999. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  4000. // Add byte code for the statement
  4001. LineInstr(bc, wnode->lastChild->tokenPos);
  4002. bc->AddCode(&whileBC);
  4003. // Jump to the expression
  4004. bc->InstrINT(asBC_JMP, beforeLabel);
  4005. // Add label after the statement
  4006. bc->Label((short)afterLabel);
  4007. continueLabels.PopLast();
  4008. breakLabels.PopLast();
  4009. RemoveVariableScope();
  4010. }
  4011. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  4012. {
  4013. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  4014. AddVariableScope(true, true);
  4015. // We will use two labels for the while loop
  4016. int beforeLabel = nextLabel++;
  4017. int beforeTest = nextLabel++;
  4018. int afterLabel = nextLabel++;
  4019. continueLabels.PushLast(beforeTest);
  4020. breakLabels.PushLast(afterLabel);
  4021. // Add label before the statement
  4022. bc->Label((short)beforeLabel);
  4023. // Compile statement
  4024. bool hasReturn;
  4025. asCByteCode whileBC(engine);
  4026. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  4027. // Add byte code for the statement
  4028. LineInstr(bc, wnode->firstChild->tokenPos);
  4029. bc->AddCode(&whileBC);
  4030. // Add label before the expression
  4031. bc->Label((short)beforeTest);
  4032. // Add a suspend bytecode inside the loop to guarantee
  4033. // that the application can suspend the execution
  4034. bc->Instr(asBC_SUSPEND);
  4035. bc->InstrPTR(asBC_JitEntry, 0);
  4036. // Add a line instruction
  4037. LineInstr(bc, wnode->lastChild->tokenPos);
  4038. // Compile expression
  4039. asCExprContext expr(engine);
  4040. CompileAssignment(wnode->lastChild, &expr);
  4041. // Allow value types to be converted to bool using 'bool opImplConv()'
  4042. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  4043. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  4044. if (!expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)))
  4045. {
  4046. asCString str;
  4047. str.Format(TXT_EXPR_MUST_BE_BOOL_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf());
  4048. Error(str, wnode->firstChild);
  4049. }
  4050. else
  4051. {
  4052. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  4053. return;
  4054. ConvertToVariable(&expr);
  4055. ProcessDeferredParams(&expr);
  4056. // Jump to next iteration if expression is true
  4057. expr.bc.InstrSHORT(asBC_CpyVtoR4, (short)expr.type.stackOffset);
  4058. expr.bc.Instr(asBC_ClrHi);
  4059. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  4060. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4061. expr.bc.OptimizeLocally(tempVariableOffsets);
  4062. bc->AddCode(&expr.bc);
  4063. }
  4064. // Add label after the statement
  4065. bc->Label((short)afterLabel);
  4066. continueLabels.PopLast();
  4067. breakLabels.PopLast();
  4068. RemoveVariableScope();
  4069. }
  4070. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  4071. {
  4072. if( breakLabels.GetLength() == 0 )
  4073. {
  4074. Error(TXT_INVALID_BREAK, node);
  4075. return;
  4076. }
  4077. // Add destructor calls for all variables that will go out of scope
  4078. // Put this clean up in a block to allow exception handler to understand them
  4079. bc->Block(true);
  4080. asCVariableScope *vs = variables;
  4081. while( !vs->isBreakScope )
  4082. {
  4083. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4084. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4085. vs = vs->parent;
  4086. }
  4087. bc->Block(false);
  4088. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  4089. }
  4090. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  4091. {
  4092. if( continueLabels.GetLength() == 0 )
  4093. {
  4094. Error(TXT_INVALID_CONTINUE, node);
  4095. return;
  4096. }
  4097. // Add destructor calls for all variables that will go out of scope
  4098. // Put this clean up in a block to allow exception handler to understand them
  4099. bc->Block(true);
  4100. asCVariableScope *vs = variables;
  4101. while( !vs->isContinueScope )
  4102. {
  4103. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4104. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4105. vs = vs->parent;
  4106. }
  4107. bc->Block(false);
  4108. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  4109. }
  4110. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  4111. {
  4112. if( enode->firstChild )
  4113. {
  4114. // Compile the expression
  4115. asCExprContext expr(engine);
  4116. CompileAssignment(enode->firstChild, &expr);
  4117. // Must not have unused ambiguous names
  4118. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  4119. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  4120. // Must not have unused anonymous functions
  4121. if( expr.IsLambda() )
  4122. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  4123. // If we get here and there is still an unprocessed property
  4124. // accessor, then process it as a get access. Don't call if there is
  4125. // already a compile error, or we might report an error that is not valid
  4126. if( !hasCompileErrors )
  4127. if( ProcessPropertyGetAccessor(&expr, enode) < 0 )
  4128. return;
  4129. // Pop the value from the stack
  4130. if( !expr.type.dataType.IsPrimitive() )
  4131. expr.bc.Instr(asBC_PopPtr);
  4132. // Release temporary variables used by expression
  4133. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4134. ProcessDeferredParams(&expr);
  4135. expr.bc.OptimizeLocally(tempVariableOffsets);
  4136. bc->AddCode(&expr.bc);
  4137. }
  4138. }
  4139. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  4140. {
  4141. // The input can be either an object or funcdef, either as handle or reference
  4142. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  4143. // If the object already is stored in temporary variable then nothing needs to be done
  4144. // Note, a type can be temporary without being a variable, in which case it is holding off
  4145. // on releasing a previously used object.
  4146. if( ctx->type.isTemporary && ctx->type.isVariable &&
  4147. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  4148. {
  4149. // If the temporary object is currently not a reference
  4150. // the expression needs to be reevaluated to a reference
  4151. if( !ctx->type.dataType.IsReference() )
  4152. {
  4153. ctx->bc.Instr(asBC_PopPtr);
  4154. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  4155. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4156. }
  4157. return;
  4158. }
  4159. // Allocate temporary variable
  4160. asCDataType dt = ctx->type.dataType;
  4161. dt.MakeReference(false);
  4162. dt.MakeReadOnly(false);
  4163. int offset = AllocateVariable(dt, true, forceOnHeap);
  4164. // Objects stored on the stack are not considered references
  4165. dt.MakeReference(IsVariableOnHeap(offset));
  4166. asCExprValue lvalue;
  4167. lvalue.Set(dt);
  4168. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  4169. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4170. bool prevIsTemp = ctx->type.isTemporary;
  4171. int prevStackOffset = ctx->type.stackOffset;
  4172. asCExprContext tmp(engine);
  4173. CompileInitAsCopy(dt, offset, &tmp, ctx, node, false);
  4174. MergeExprBytecode(ctx, &tmp);
  4175. // Release the previous temporary variable if it hasn't already been released
  4176. if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
  4177. ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
  4178. // Push the reference to the temporary variable on the stack
  4179. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4180. ctx->type.Set(dt);
  4181. ctx->type.isTemporary = true;
  4182. ctx->type.stackOffset = (short)offset;
  4183. ctx->type.isVariable = true;
  4184. ctx->type.isExplicitHandle = isExplicitHandle;
  4185. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4186. }
  4187. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  4188. {
  4189. // Get return type and location
  4190. sVariable *v = variables->GetVariable("return");
  4191. // Basic validations
  4192. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  4193. {
  4194. Error(TXT_MUST_RETURN_VALUE, rnode);
  4195. return;
  4196. }
  4197. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  4198. {
  4199. Error(TXT_CANT_RETURN_VALUE, rnode);
  4200. return;
  4201. }
  4202. // Compile the expression
  4203. if( rnode->firstChild )
  4204. {
  4205. // Compile the expression
  4206. asCExprContext expr(engine);
  4207. int r = CompileAssignment(rnode->firstChild, &expr);
  4208. if( r < 0 ) return;
  4209. if( v->type.IsReference() )
  4210. {
  4211. // The expression that gives the reference must not use any of the
  4212. // variables that must be destroyed upon exit, because then it means
  4213. // reference will stay alive while the clean-up is done, which could
  4214. // potentially mean that the reference is invalidated by the clean-up.
  4215. //
  4216. // When the function is returning a reference, the clean-up of the
  4217. // variables must be done before the evaluation of the expression.
  4218. //
  4219. // A reference to a global variable, or a class member for class methods
  4220. // should be allowed to be returned.
  4221. if( !(expr.type.dataType.IsReference() ||
  4222. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  4223. {
  4224. // Clean up the potential deferred parameters
  4225. ProcessDeferredParams(&expr);
  4226. Error(TXT_NOT_VALID_REFERENCE, rnode);
  4227. return;
  4228. }
  4229. // No references to local variables, temporary variables, or parameters
  4230. // are allowed to be returned, since they go out of scope when the function
  4231. // returns. Even reference parameters are disallowed, since it is not possible
  4232. // to know the scope of them. The exception is the 'this' pointer, which
  4233. // is treated by the compiler as a local variable, but isn't really so.
  4234. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  4235. {
  4236. // Clean up the potential deferred parameters
  4237. ProcessDeferredParams(&expr);
  4238. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  4239. return;
  4240. }
  4241. // The type must match exactly as we cannot convert
  4242. // the reference without loosing the original value
  4243. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  4244. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  4245. !expr.type.dataType.IsObjectHandle() &&
  4246. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  4247. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4248. {
  4249. // Clean up the potential deferred parameters
  4250. ProcessDeferredParams(&expr);
  4251. asCString str;
  4252. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4253. Error(str, rnode);
  4254. return;
  4255. }
  4256. // The expression must not have any deferred expressions, because the evaluation
  4257. // of these cannot be done without keeping the reference which is not safe
  4258. if( expr.deferredParams.GetLength() )
  4259. {
  4260. // Clean up the potential deferred parameters
  4261. ProcessDeferredParams(&expr);
  4262. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4263. return;
  4264. }
  4265. // Make sure the expression isn't using any local variables that
  4266. // will need to be cleaned up before the function completes
  4267. asCArray<int> usedVars;
  4268. expr.bc.GetVarsUsed(usedVars);
  4269. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4270. {
  4271. int var = GetVariableSlot(usedVars[n]);
  4272. if( var != -1 )
  4273. {
  4274. asCDataType dt = variableAllocations[var];
  4275. if( dt.IsObject() )
  4276. {
  4277. ProcessDeferredParams(&expr);
  4278. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4279. return;
  4280. }
  4281. }
  4282. }
  4283. // Can't return the reference if could point to a local variable
  4284. if( expr.type.isRefToLocal )
  4285. {
  4286. ProcessDeferredParams(&expr);
  4287. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4288. return;
  4289. }
  4290. // All objects in the function must be cleaned up before the expression
  4291. // is evaluated, otherwise there is a possibility that the cleanup will
  4292. // invalidate the reference.
  4293. // Destroy the local variables before loading
  4294. // the reference into the register. This will
  4295. // be done before the expression is evaluated.
  4296. DestroyVariables(bc);
  4297. // For primitives the reference is already in the register,
  4298. // but for non-primitives the reference is on the stack so we
  4299. // need to load it into the register
  4300. if( !expr.type.dataType.IsPrimitive() )
  4301. {
  4302. if( !expr.type.dataType.IsObjectHandle() &&
  4303. expr.type.dataType.IsReference() )
  4304. expr.bc.Instr(asBC_RDSPtr);
  4305. expr.bc.Instr(asBC_PopRPtr);
  4306. }
  4307. // There are no temporaries to release so we're done
  4308. }
  4309. else // if( !v->type.IsReference() )
  4310. {
  4311. if( ProcessPropertyGetAccessor(&expr, rnode) < 0 )
  4312. return;
  4313. // Prepare the value for assignment
  4314. IsVariableInitialized(&expr.type, rnode->firstChild);
  4315. if( v->type.IsPrimitive() )
  4316. {
  4317. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4318. // Implicitly convert the value to the return type
  4319. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4320. // Verify that the conversion was successful
  4321. if( expr.type.dataType != v->type )
  4322. {
  4323. asCString str;
  4324. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4325. Error(str, rnode);
  4326. return;
  4327. }
  4328. else
  4329. {
  4330. ConvertToVariable(&expr);
  4331. // Clean up the local variables and process deferred parameters
  4332. DestroyVariables(&expr.bc);
  4333. ProcessDeferredParams(&expr);
  4334. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4335. // Load the variable in the register
  4336. if( v->type.GetSizeOnStackDWords() == 1 )
  4337. expr.bc.InstrSHORT(asBC_CpyVtoR4, (short)expr.type.stackOffset);
  4338. else
  4339. expr.bc.InstrSHORT(asBC_CpyVtoR8, (short)expr.type.stackOffset);
  4340. }
  4341. }
  4342. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4343. {
  4344. // Value types are returned on the stack, in a location
  4345. // that has been reserved by the calling function.
  4346. if( outFunc->DoesReturnOnStack() )
  4347. {
  4348. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4349. // it should be called directly instead of first converting the expression and
  4350. // then copy the value.
  4351. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4352. {
  4353. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4354. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4355. {
  4356. asCString str;
  4357. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4358. Error(str, rnode->firstChild);
  4359. return;
  4360. }
  4361. }
  4362. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4363. asCExprContext tmp(engine);
  4364. CompileInitAsCopy(v->type, offset, &tmp, &expr, rnode->firstChild, true);
  4365. MergeExprBytecode(&expr, &tmp);
  4366. // Clean up the local variables and process deferred parameters
  4367. DestroyVariables(&expr.bc);
  4368. ProcessDeferredParams(&expr);
  4369. // If this return statement is within a branch, there might be more statements after this. To avoid having the exception
  4370. // handler think the object is live in the statements between the return and the end of the function we need to add a marker
  4371. expr.bc.ObjInfo(offset, asOBJ_UNINIT);
  4372. }
  4373. else
  4374. {
  4375. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4376. // Prepare the expression to be loaded into the object
  4377. // register. This will place the reference in local variable
  4378. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4379. // Pop the reference to the temporary variable
  4380. expr.bc.Instr(asBC_PopPtr);
  4381. // Clean up the local variables and process deferred parameters
  4382. DestroyVariables(&expr.bc);
  4383. ProcessDeferredParams(&expr);
  4384. // Load the object pointer into the object register
  4385. // LOADOBJ also clears the address in the variable
  4386. expr.bc.InstrSHORT(asBC_LOADOBJ, (short)expr.type.stackOffset);
  4387. // LOADOBJ cleared the address in the variable so the object will not be freed
  4388. // here, but the temporary variable must still be freed so the slot can be reused
  4389. // By releasing without the bytecode we do just that.
  4390. ReleaseTemporaryVariable(expr.type, 0);
  4391. }
  4392. }
  4393. }
  4394. expr.bc.OptimizeLocally(tempVariableOffsets);
  4395. bc->AddCode(&expr.bc);
  4396. }
  4397. else
  4398. {
  4399. // For functions that don't return anything
  4400. // we just detroy the local variables
  4401. DestroyVariables(bc);
  4402. }
  4403. // Jump to the end of the function
  4404. bc->InstrINT(asBC_JMP, 0);
  4405. }
  4406. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4407. {
  4408. // Call destructor on all variables except for the function parameters
  4409. // Put the clean-up in a block to allow exception handler to understand this
  4410. bc->Block(true);
  4411. asCVariableScope *vs = variables;
  4412. while( vs )
  4413. {
  4414. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4415. if( vs->variables[n]->stackOffset > 0 )
  4416. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4417. vs = vs->parent;
  4418. }
  4419. bc->Block(false);
  4420. }
  4421. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4422. {
  4423. variables = asNEW(asCVariableScope)(variables);
  4424. if( variables == 0 )
  4425. {
  4426. // Out of memory
  4427. return;
  4428. }
  4429. variables->isBreakScope = isBreakScope;
  4430. variables->isContinueScope = isContinueScope;
  4431. }
  4432. void asCCompiler::RemoveVariableScope()
  4433. {
  4434. if( variables )
  4435. {
  4436. asCVariableScope *var = variables;
  4437. variables = variables->parent;
  4438. asDELETE(var,asCVariableScope);
  4439. }
  4440. }
  4441. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4442. {
  4443. asCString str;
  4444. int r = 0, c = 0;
  4445. asASSERT( node );
  4446. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4447. builder->WriteError(script->name, msg, r, c);
  4448. hasCompileErrors = true;
  4449. }
  4450. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4451. {
  4452. asCString str;
  4453. int r = 0, c = 0;
  4454. asASSERT( node );
  4455. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4456. builder->WriteWarning(script->name, msg, r, c);
  4457. }
  4458. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4459. {
  4460. asCString str;
  4461. int r = 0, c = 0;
  4462. asASSERT( node );
  4463. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4464. builder->WriteInfo(script->name, msg, r, c, false);
  4465. }
  4466. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4467. {
  4468. int r = 0, c = 0;
  4469. asASSERT( node );
  4470. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4471. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4472. {
  4473. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4474. if( inType && func->funcType == asFUNC_VIRTUAL )
  4475. func = inType->virtualFunctionTable[func->vfTableIdx];
  4476. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4477. if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE))
  4478. {
  4479. // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user
  4480. for (unsigned int p = 0; p < func->GetParamCount(); p++)
  4481. {
  4482. int typeId = 0;
  4483. func->GetParam(p, &typeId);
  4484. asITypeInfo *ti = engine->GetTypeInfoById(typeId);
  4485. if (ti && (ti->GetFlags() & asOBJ_FUNCDEF))
  4486. {
  4487. asCString msg;
  4488. msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration());
  4489. builder->WriteInfo(script->name, msg.AddressOf(), r, c, false);
  4490. }
  4491. }
  4492. }
  4493. }
  4494. }
  4495. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4496. {
  4497. int l = int(reservedVariables.GetLength());
  4498. ctx->bc.GetVarsUsed(reservedVariables);
  4499. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4500. reservedVariables.SetLength(l);
  4501. return var;
  4502. }
  4503. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference)
  4504. {
  4505. asCDataType t(type);
  4506. t.MakeReference(asReference);
  4507. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4508. t.SetTokenType(ttInt);
  4509. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4510. t.SetTokenType(ttDouble);
  4511. // Only null handles have the token type unrecognized token
  4512. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4513. bool isOnHeap = true;
  4514. if( t.IsPrimitive() ||
  4515. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap && !asReference) )
  4516. {
  4517. // Primitives and value types (unless overridden) are allocated on the stack
  4518. isOnHeap = false;
  4519. }
  4520. // Find a free location with the same type
  4521. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4522. {
  4523. int slot = freeVariables[n];
  4524. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4525. variableIsTemporary[slot] == isTemporary &&
  4526. variableIsOnHeap[slot] == isOnHeap )
  4527. {
  4528. // We can't return by slot, must count variable sizes
  4529. int offset = GetVariableOffset(slot);
  4530. // Verify that it is not in the list of reserved variables
  4531. bool isUsed = false;
  4532. if( reservedVariables.GetLength() )
  4533. isUsed = reservedVariables.Exists(offset);
  4534. if( !isUsed )
  4535. {
  4536. if( n != freeVariables.GetLength() - 1 )
  4537. freeVariables[n] = freeVariables.PopLast();
  4538. else
  4539. freeVariables.PopLast();
  4540. if( isTemporary )
  4541. tempVariables.PushLast(offset);
  4542. return offset;
  4543. }
  4544. }
  4545. }
  4546. variableAllocations.PushLast(t);
  4547. variableIsTemporary.PushLast(isTemporary);
  4548. variableIsOnHeap.PushLast(isOnHeap);
  4549. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4550. if( isTemporary )
  4551. {
  4552. // Add offset to the currently allocated temporary variables
  4553. tempVariables.PushLast(offset);
  4554. // Add offset to all known offsets to temporary variables, whether allocated or not
  4555. tempVariableOffsets.PushLast(offset);
  4556. }
  4557. return offset;
  4558. }
  4559. int asCCompiler::GetVariableOffset(int varIndex)
  4560. {
  4561. // Return offset to the last dword on the stack
  4562. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4563. int varOffset = 1;
  4564. // Skip lower variables
  4565. for( int n = 0; n < varIndex; n++ )
  4566. {
  4567. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4568. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4569. else
  4570. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4571. }
  4572. if( varIndex < (int)variableAllocations.GetLength() )
  4573. {
  4574. // For variables larger than 1 dword the returned offset should be to the last dword
  4575. int size;
  4576. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4577. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4578. else
  4579. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4580. if( size > 1 )
  4581. varOffset += size-1;
  4582. }
  4583. return varOffset;
  4584. }
  4585. int asCCompiler::GetVariableSlot(int offset)
  4586. {
  4587. int varOffset = 1;
  4588. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4589. {
  4590. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4591. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4592. else
  4593. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4594. if( varOffset == offset )
  4595. return n;
  4596. varOffset++;
  4597. }
  4598. return -1;
  4599. }
  4600. bool asCCompiler::IsVariableOnHeap(int offset)
  4601. {
  4602. int varSlot = GetVariableSlot(offset);
  4603. if( varSlot < 0 )
  4604. {
  4605. // This happens for function arguments that are considered as on the heap
  4606. return true;
  4607. }
  4608. return variableIsOnHeap[varSlot];
  4609. }
  4610. void asCCompiler::DeallocateVariable(int offset)
  4611. {
  4612. // Remove temporary variable
  4613. int n;
  4614. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4615. {
  4616. if( offset == tempVariables[n] )
  4617. {
  4618. if( n == (int)tempVariables.GetLength()-1 )
  4619. tempVariables.PopLast();
  4620. else
  4621. tempVariables[n] = tempVariables.PopLast();
  4622. break;
  4623. }
  4624. }
  4625. // Mark the variable slot available for new allocations
  4626. n = GetVariableSlot(offset);
  4627. if( n != -1 )
  4628. {
  4629. freeVariables.PushLast(n);
  4630. return;
  4631. }
  4632. // We might get here if the variable was implicitly declared
  4633. // because it was used before a formal declaration, in this case
  4634. // the offset is 0x7FFF
  4635. asASSERT(offset == 0x7FFF);
  4636. }
  4637. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4638. {
  4639. if( t.isTemporary )
  4640. {
  4641. ReleaseTemporaryVariable(t.stackOffset, bc);
  4642. t.isTemporary = false;
  4643. }
  4644. }
  4645. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4646. {
  4647. asASSERT( tempVariables.Exists(offset) );
  4648. if( bc )
  4649. {
  4650. // We need to call the destructor on the true variable type
  4651. int n = GetVariableSlot(offset);
  4652. asASSERT( n >= 0 );
  4653. if( n >= 0 )
  4654. {
  4655. asCDataType dt = variableAllocations[n];
  4656. bool isOnHeap = variableIsOnHeap[n];
  4657. // Call destructor
  4658. CallDestructor(dt, offset, isOnHeap, bc);
  4659. }
  4660. }
  4661. DeallocateVariable(offset);
  4662. }
  4663. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4664. {
  4665. if( ctx->type.dataType.IsReference() )
  4666. {
  4667. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4668. {
  4669. ctx->type.dataType.MakeReference(false);
  4670. if( generateCode )
  4671. ctx->bc.Instr(asBC_RDSPtr);
  4672. }
  4673. else
  4674. {
  4675. // This should never happen as primitives are treated differently
  4676. asASSERT(false);
  4677. }
  4678. }
  4679. }
  4680. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4681. {
  4682. // No need to check if there is no variable scope
  4683. if( variables == 0 ) return true;
  4684. // Temporary variables are assumed to be initialized
  4685. if( type->isTemporary ) return true;
  4686. // Verify that it is a variable
  4687. if( !type->isVariable ) return true;
  4688. // Find the variable
  4689. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4690. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4691. if( v == 0 ) return true;
  4692. if( v->isInitialized ) return true;
  4693. // Complex types don't need this test
  4694. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4695. // Mark as initialized so that the user will not be bothered again
  4696. v->isInitialized = true;
  4697. // Write warning
  4698. asCString str;
  4699. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4700. Warning(str, node);
  4701. return false;
  4702. }
  4703. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4704. {
  4705. // Check if the variable is initialized (if it indeed is a variable)
  4706. IsVariableInitialized(&ctx->type, node);
  4707. asCDataType to = ctx->type.dataType;
  4708. to.MakeReference(false);
  4709. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4710. ProcessDeferredParams(ctx);
  4711. }
  4712. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4713. {
  4714. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4715. int l = int(reservedVariables.GetLength());
  4716. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4717. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  4718. return;
  4719. // Don't allow any operators on void expressions
  4720. if (rctx->type.IsVoid())
  4721. {
  4722. asCString str;
  4723. str.Format(TXT_DATA_TYPE_CANT_BE_s, "void");
  4724. Error(str, node);
  4725. rctx->type.SetDummy();
  4726. return;
  4727. }
  4728. // Make sure the rvalue is initialized if it is a variable
  4729. IsVariableInitialized(&rctx->type, node);
  4730. if( lvalue->IsPrimitive() )
  4731. {
  4732. if( rctx->type.dataType.IsPrimitive() )
  4733. {
  4734. if( rctx->type.dataType.IsReference() )
  4735. {
  4736. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4737. ConvertToVariableNotIn(rctx, lvalueExpr);
  4738. }
  4739. }
  4740. // Implicitly convert the value to the right type
  4741. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4742. // Check data type
  4743. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4744. {
  4745. asCString str;
  4746. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4747. Error(str, node);
  4748. rctx->type.SetDummy();
  4749. }
  4750. // Make sure the rvalue is a variable
  4751. if( !rctx->type.isVariable )
  4752. ConvertToVariableNotIn(rctx, lvalueExpr);
  4753. }
  4754. else
  4755. {
  4756. asCDataType to = *lvalue;
  4757. to.MakeReference(false);
  4758. // TODO: ImplicitConversion should know to do this by itself
  4759. // First convert to a handle which will do a reference cast
  4760. if( !lvalue->IsObjectHandle() &&
  4761. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4762. to.MakeHandle(true);
  4763. // Don't allow the implicit conversion to create an object
  4764. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4765. if( !lvalue->IsObjectHandle() &&
  4766. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4767. {
  4768. // Then convert to a reference, which will validate the handle
  4769. to.MakeHandle(false);
  4770. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4771. }
  4772. // Check data type
  4773. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4774. {
  4775. asCString str;
  4776. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4777. Error(str, node);
  4778. }
  4779. else
  4780. {
  4781. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4782. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4783. }
  4784. }
  4785. // Unreserve variables
  4786. reservedVariables.SetLength(l);
  4787. }
  4788. bool asCCompiler::IsLValue(asCExprValue &type)
  4789. {
  4790. if( !type.isLValue ) return false;
  4791. if( type.dataType.IsReadOnly() ) return false;
  4792. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4793. return true;
  4794. }
  4795. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4796. {
  4797. if( lvalue->dataType.IsReadOnly() )
  4798. {
  4799. Error(TXT_REF_IS_READ_ONLY, node);
  4800. return -1;
  4801. }
  4802. if( lvalue->dataType.IsPrimitive() )
  4803. {
  4804. if( lvalue->isVariable )
  4805. {
  4806. // Copy the value between the variables directly
  4807. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4808. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4809. else
  4810. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4811. // Mark variable as initialized
  4812. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4813. if( v ) v->isInitialized = true;
  4814. }
  4815. else if( lvalue->dataType.IsReference() )
  4816. {
  4817. // Copy the value of the variable to the reference in the register
  4818. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4819. if( s == 1 )
  4820. bc->InstrSHORT(asBC_WRTV1, (short)rvalue->stackOffset);
  4821. else if( s == 2 )
  4822. bc->InstrSHORT(asBC_WRTV2, (short)rvalue->stackOffset);
  4823. else if( s == 4 )
  4824. bc->InstrSHORT(asBC_WRTV4, (short)rvalue->stackOffset);
  4825. else if( s == 8 )
  4826. bc->InstrSHORT(asBC_WRTV8, (short)rvalue->stackOffset);
  4827. }
  4828. else
  4829. {
  4830. Error(TXT_NOT_VALID_LVALUE, node);
  4831. return -1;
  4832. }
  4833. }
  4834. else if( !lvalue->isExplicitHandle )
  4835. {
  4836. asCExprContext ctx(engine);
  4837. ctx.type = *lvalue;
  4838. Dereference(&ctx, true);
  4839. *lvalue = ctx.type;
  4840. bc->AddCode(&ctx.bc);
  4841. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4842. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4843. {
  4844. asCExprContext res(engine);
  4845. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4846. bc->AddCode(&res.bc);
  4847. *lvalue = res.type;
  4848. }
  4849. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4850. {
  4851. // Call the default copy operator for script classes
  4852. // This is done differently because the default copy operator
  4853. // is registered as returning int&, but in reality it returns
  4854. // a reference to the object.
  4855. // TODO: Avoid this special case by implementing a copystub for
  4856. // script classes that uses the default copy operator
  4857. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4858. bc->Instr(asBC_PshRPtr);
  4859. }
  4860. else
  4861. {
  4862. // Default copy operator
  4863. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4864. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4865. {
  4866. asCString msg;
  4867. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4868. Error(msg, node);
  4869. return -1;
  4870. }
  4871. // Copy larger data types from a reference
  4872. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4873. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4874. }
  4875. }
  4876. else
  4877. {
  4878. // TODO: The object handle can be stored in a variable as well
  4879. if( !lvalue->dataType.IsReference() )
  4880. {
  4881. Error(TXT_NOT_VALID_REFERENCE, node);
  4882. return -1;
  4883. }
  4884. if( lvalue->dataType.IsFuncdef() )
  4885. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4886. else
  4887. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4888. // Mark variable as initialized
  4889. if( variables )
  4890. {
  4891. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4892. if( v ) v->isInitialized = true;
  4893. }
  4894. }
  4895. return 0;
  4896. }
  4897. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4898. {
  4899. bool conversionDone = false;
  4900. asCArray<int> ops;
  4901. // A ref cast must not remove the constness
  4902. bool isConst = ctx->type.dataType.IsObjectConst();
  4903. // Find a suitable opCast or opImplCast method
  4904. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4905. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4906. {
  4907. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4908. if( (isExplicit && func->name == "opCast") ||
  4909. func->name == "opImplCast" )
  4910. {
  4911. // Is the operator for the output type?
  4912. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4913. continue;
  4914. // Can't call a non-const function on a const object
  4915. if( isConst && !func->IsReadOnly() )
  4916. continue;
  4917. ops.PushLast(func->id);
  4918. }
  4919. }
  4920. // Filter the list by constness to remove const methods if there are matching non-const methods
  4921. FilterConst(ops, !isConst);
  4922. // If there is multiple matches, then pick the most appropriate one
  4923. if (ops.GetLength() > 1)
  4924. {
  4925. // This should only happen if an explicit cast is compiled
  4926. // and the type has both the opCast and opImplCast
  4927. asASSERT(isExplicit);
  4928. asASSERT(ops.GetLength() == 2);
  4929. for (asUINT n = 0; n < ops.GetLength(); n++)
  4930. {
  4931. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4932. if (func->name == "opImplCast")
  4933. {
  4934. ops.RemoveIndex(n);
  4935. n--;
  4936. }
  4937. }
  4938. }
  4939. // Should only have one behaviour for each output type
  4940. if( ops.GetLength() == 1 )
  4941. {
  4942. conversionDone = true;
  4943. if( generateCode )
  4944. {
  4945. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4946. // null, we can create a special CALLSYS instruction that checks
  4947. // if the object pointer is null and if so sets the object register
  4948. // to null directly without executing the function.
  4949. //
  4950. // Alternatively I could force the ref cast behaviours be global
  4951. // functions with 1 parameter, even though they should still be
  4952. // registered with RegisterObjectBehaviour()
  4953. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4954. {
  4955. // Add code to avoid calling the cast behaviour if the handle is already null,
  4956. // because that will raise a null pointer exception due to the cast behaviour
  4957. // being a class method, and the this pointer cannot be null.
  4958. if (!ctx->type.isVariable)
  4959. {
  4960. Dereference(ctx, true);
  4961. ConvertToVariable(ctx);
  4962. }
  4963. // The reference on the stack will not be used
  4964. ctx->bc.Instr(asBC_PopPtr);
  4965. // TODO: runtime optimize: should have immediate comparison for null pointer
  4966. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4967. // 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)
  4968. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4969. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4970. DeallocateVariable(offset);
  4971. int afterLabel = nextLabel++;
  4972. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4973. // Call the cast operator
  4974. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  4975. ctx->bc.Instr(asBC_RDSPtr);
  4976. ctx->type.dataType.MakeReference(false);
  4977. asCArray<asCExprContext *> args;
  4978. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4979. ctx->bc.Instr(asBC_PopPtr);
  4980. int endLabel = nextLabel++;
  4981. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4982. ctx->bc.Label((short)afterLabel);
  4983. // Make a NULL pointer
  4984. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)ctx->type.stackOffset);
  4985. ctx->bc.Label((short)endLabel);
  4986. // Push the reference to the handle on the stack
  4987. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  4988. }
  4989. else
  4990. {
  4991. // Value types cannot be null, so there is no need to check for this.
  4992. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4993. // as those are only expected as registered global properties that cannot
  4994. // be modified anyway.
  4995. // Call the cast operator
  4996. asCArray<asCExprContext *> args;
  4997. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4998. }
  4999. }
  5000. else
  5001. {
  5002. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  5003. ctx->type.Set(func->returnType);
  5004. }
  5005. }
  5006. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() )
  5007. {
  5008. // Check for the generic ref cast method: void opCast(?&out)
  5009. // This option only works if the expected type is a handle
  5010. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  5011. {
  5012. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5013. if( (isExplicit && func->name == "opCast") ||
  5014. func->name == "opImplCast" )
  5015. {
  5016. // Does the operator take the ?&out parameter?
  5017. if( func->returnType.GetTokenType() != ttVoid ||
  5018. func->parameterTypes.GetLength() != 1 ||
  5019. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5020. func->inOutFlags[0] != asTM_OUTREF )
  5021. continue;
  5022. ops.PushLast(func->id);
  5023. }
  5024. }
  5025. // Filter the list by constness to remove const methods if there are matching non-const methods
  5026. FilterConst(ops, !isConst);
  5027. // If there is multiple matches, then pick the most appropriate one
  5028. if (ops.GetLength() > 1)
  5029. {
  5030. // This should only happen if an explicit cast is compiled
  5031. // and the type has both the opCast and opImplCast
  5032. asASSERT(isExplicit);
  5033. asASSERT(ops.GetLength() == 2);
  5034. for (asUINT n = 0; n < ops.GetLength(); n++)
  5035. {
  5036. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  5037. if (func->name == "opImplCast")
  5038. {
  5039. ops.RemoveIndex(n);
  5040. n--;
  5041. }
  5042. }
  5043. }
  5044. if( ops.GetLength() == 1 )
  5045. {
  5046. conversionDone = true;
  5047. if( generateCode )
  5048. {
  5049. int afterLabel = 0;
  5050. bool doNullCheck = false;
  5051. bool releaseTempVariable = false;
  5052. asCExprContext tmp(engine);
  5053. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  5054. {
  5055. tmp.bc.AddCode(&ctx->bc);
  5056. tmp.Merge(ctx);
  5057. // Add code to avoid calling the cast behaviour if the handle is already null,
  5058. // because that will raise a null pointer exception due to the cast behaviour
  5059. // being a class method, and the this pointer cannot be null.
  5060. doNullCheck = true;
  5061. if (!ctx->type.isVariable)
  5062. {
  5063. Dereference(&tmp, true);
  5064. ConvertToVariable(&tmp);
  5065. releaseTempVariable = true;
  5066. }
  5067. // The reference on the stack will not be used
  5068. tmp.bc.Instr(asBC_PopPtr);
  5069. // TODO: runtime optimize: should have immediate comparison for null pointer
  5070. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  5071. // 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)
  5072. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  5073. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  5074. DeallocateVariable(offset);
  5075. afterLabel = nextLabel++;
  5076. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  5077. // Place the object pointer on the stack
  5078. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  5079. }
  5080. // Allocate a temporary variable of the requested handle type
  5081. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5082. // Pass the reference of that variable to the function as output parameter
  5083. asCDataType toRef(to);
  5084. toRef.MakeReference(true);
  5085. asCArray<asCExprContext *> args;
  5086. asCExprContext arg(engine);
  5087. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5088. // Don't mark the variable as temporary, so it won't be freed too early
  5089. arg.type.SetVariable(toRef, stackOffset, false);
  5090. arg.type.isLValue = true;
  5091. arg.type.isExplicitHandle = true;
  5092. args.PushLast(&arg);
  5093. // Call the behaviour method
  5094. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5095. if (doNullCheck)
  5096. {
  5097. // Add the call after the null check
  5098. tmp.bc.AddCode(&ctx->bc);
  5099. ctx->bc.AddCode(&tmp.bc);
  5100. int endLabel = nextLabel++;
  5101. ctx->bc.InstrINT(asBC_JMP, endLabel);
  5102. ctx->bc.Label((short)afterLabel);
  5103. // Make a NULL pointer
  5104. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  5105. ctx->bc.Label((short)endLabel);
  5106. }
  5107. // If a temporary variable was allocated in the tmp to convert
  5108. // the input expression to a variable, it must be released here
  5109. if (releaseTempVariable && tmp.type.isTemporary)
  5110. ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
  5111. // Use the reference to the variable as the result of the expression
  5112. // Now we can mark the variable as temporary
  5113. ctx->type.SetVariable(toRef, stackOffset, true);
  5114. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5115. }
  5116. else
  5117. {
  5118. // All casts are legal
  5119. ctx->type.Set(to);
  5120. }
  5121. }
  5122. }
  5123. // If the script object didn't implement a matching opCast or opImplCast
  5124. // then check if the desired type is part of the hierarchy
  5125. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  5126. {
  5127. // We need it to be a reference
  5128. if( !ctx->type.dataType.IsReference() )
  5129. {
  5130. asCDataType toRef = ctx->type.dataType;
  5131. toRef.MakeReference(true);
  5132. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  5133. }
  5134. if( isExplicit )
  5135. {
  5136. // Allow dynamic cast between object handles (only for script objects).
  5137. // At run time this may result in a null handle,
  5138. // which when used will throw an exception
  5139. conversionDone = true;
  5140. if( generateCode )
  5141. {
  5142. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  5143. // Allocate a temporary variable for the returned object
  5144. int returnOffset = AllocateVariable(to, true);
  5145. // Move the pointer from the object register to the temporary variable
  5146. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  5147. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  5148. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5149. ctx->type.SetVariable(to, returnOffset, true);
  5150. ctx->type.dataType.MakeReference(true);
  5151. }
  5152. else
  5153. {
  5154. ctx->type.dataType = to;
  5155. ctx->type.dataType.MakeReference(true);
  5156. }
  5157. }
  5158. else
  5159. {
  5160. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  5161. {
  5162. conversionDone = true;
  5163. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5164. }
  5165. }
  5166. // A ref cast must not remove the constness
  5167. if( isConst )
  5168. ctx->type.dataType.MakeHandleToConst(true);
  5169. }
  5170. return conversionDone;
  5171. }
  5172. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5173. {
  5174. asCDataType to = toOrig;
  5175. to.MakeReference(false);
  5176. asASSERT( !ctx->type.dataType.IsReference() );
  5177. // Maybe no conversion is needed
  5178. if( to.IsEqualExceptConst(ctx->type.dataType) )
  5179. {
  5180. // A primitive is const or not
  5181. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5182. return asCC_NO_CONV;
  5183. }
  5184. // Is the conversion an ambiguous enum value?
  5185. if( ctx->enumValue != "" )
  5186. {
  5187. if( to.IsEnumType() )
  5188. {
  5189. // Attempt to resolve an ambiguous enum value
  5190. asCDataType out;
  5191. asDWORD value;
  5192. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  5193. {
  5194. ctx->type.SetConstantDW(out, value);
  5195. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5196. // Reset the enum value since we no longer need it
  5197. ctx->enumValue = "";
  5198. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  5199. return asCC_NO_CONV;
  5200. }
  5201. }
  5202. // The enum value is ambiguous
  5203. if( node && generateCode )
  5204. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  5205. // Set a dummy to allow the compiler to try to continue the conversion
  5206. ctx->type.SetDummy();
  5207. }
  5208. // Determine the cost of this conversion
  5209. asUINT cost = asCC_NO_CONV;
  5210. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5211. cost = asCC_FLOAT_TO_INT_CONV;
  5212. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  5213. cost = asCC_INT_TO_FLOAT_CONV;
  5214. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  5215. cost = asCC_ENUM_SAME_SIZE_CONV;
  5216. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  5217. cost = asCC_ENUM_DIFF_SIZE_CONV;
  5218. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  5219. cost = asCC_SIGNED_TO_UNSIGNED_CONV;
  5220. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  5221. cost = asCC_UNSIGNED_TO_SIGNED_CONV;
  5222. else if( to.GetSizeInMemoryBytes() > ctx->type.dataType.GetSizeInMemoryBytes() )
  5223. cost = asCC_PRIMITIVE_SIZE_UP_CONV;
  5224. else if (to.GetSizeInMemoryBytes() < ctx->type.dataType.GetSizeInMemoryBytes())
  5225. cost = asCC_PRIMITIVE_SIZE_DOWN_CONV;
  5226. // Start by implicitly converting constant values
  5227. if( ctx->type.isConstant )
  5228. {
  5229. ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType);
  5230. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5231. return cost;
  5232. }
  5233. // Allow implicit conversion between numbers
  5234. if( generateCode )
  5235. {
  5236. // When generating the code the decision has already been made, so we don't bother determining the cost
  5237. // Convert smaller types to 32bit first
  5238. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  5239. if( s < 4 )
  5240. {
  5241. ConvertToTempVariable(ctx);
  5242. if( ctx->type.dataType.IsIntegerType() )
  5243. {
  5244. if( s == 1 )
  5245. ctx->bc.InstrSHORT(asBC_sbTOi, (short)ctx->type.stackOffset);
  5246. else if( s == 2 )
  5247. ctx->bc.InstrSHORT(asBC_swTOi, (short)ctx->type.stackOffset);
  5248. ctx->type.dataType.SetTokenType(ttInt);
  5249. }
  5250. else if( ctx->type.dataType.IsUnsignedType() )
  5251. {
  5252. if( s == 1 )
  5253. ctx->bc.InstrSHORT(asBC_ubTOi, (short)ctx->type.stackOffset);
  5254. else if( s == 2 )
  5255. ctx->bc.InstrSHORT(asBC_uwTOi, (short)ctx->type.stackOffset);
  5256. ctx->type.dataType.SetTokenType(ttUInt);
  5257. }
  5258. }
  5259. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5260. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5261. {
  5262. if( ctx->type.dataType.IsIntegerType() ||
  5263. ctx->type.dataType.IsUnsignedType() )
  5264. {
  5265. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5266. {
  5267. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5268. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5269. }
  5270. else
  5271. {
  5272. ConvertToTempVariable(ctx);
  5273. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5274. int offset = AllocateVariable(to, true);
  5275. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5276. ctx->type.SetVariable(to, offset, true);
  5277. }
  5278. }
  5279. else if( ctx->type.dataType.IsFloatType() )
  5280. {
  5281. ConvertToTempVariable(ctx);
  5282. ctx->bc.InstrSHORT(asBC_fTOi, (short)ctx->type.stackOffset);
  5283. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5284. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5285. if( convType != asIC_EXPLICIT_VAL_CAST )
  5286. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5287. }
  5288. else if( ctx->type.dataType.IsDoubleType() )
  5289. {
  5290. ConvertToTempVariable(ctx);
  5291. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5292. int offset = AllocateVariable(to, true);
  5293. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  5294. ctx->type.SetVariable(to, offset, true);
  5295. if( convType != asIC_EXPLICIT_VAL_CAST )
  5296. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5297. }
  5298. // Convert to smaller integer if necessary
  5299. s = to.GetSizeInMemoryBytes();
  5300. if( s < 4 )
  5301. {
  5302. ConvertToTempVariable(ctx);
  5303. if( s == 1 )
  5304. ctx->bc.InstrSHORT(asBC_iTOb, (short)ctx->type.stackOffset);
  5305. else if( s == 2 )
  5306. ctx->bc.InstrSHORT(asBC_iTOw, (short)ctx->type.stackOffset);
  5307. }
  5308. }
  5309. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5310. {
  5311. if( ctx->type.dataType.IsIntegerType() ||
  5312. ctx->type.dataType.IsUnsignedType() )
  5313. {
  5314. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5315. {
  5316. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5317. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5318. }
  5319. else
  5320. {
  5321. ConvertToTempVariable(ctx);
  5322. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5323. int offset = AllocateVariable(to, true);
  5324. if( ctx->type.dataType.IsUnsignedType() )
  5325. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5326. else
  5327. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5328. ctx->type.SetVariable(to, offset, true);
  5329. }
  5330. }
  5331. else if( ctx->type.dataType.IsFloatType() )
  5332. {
  5333. ConvertToTempVariable(ctx);
  5334. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5335. int offset = AllocateVariable(to, true);
  5336. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5337. ctx->type.SetVariable(to, offset, true);
  5338. if( convType != asIC_EXPLICIT_VAL_CAST )
  5339. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5340. }
  5341. else if( ctx->type.dataType.IsDoubleType() )
  5342. {
  5343. ConvertToTempVariable(ctx);
  5344. ctx->bc.InstrSHORT(asBC_dTOi64, (short)ctx->type.stackOffset);
  5345. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5346. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5347. if( convType != asIC_EXPLICIT_VAL_CAST )
  5348. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5349. }
  5350. }
  5351. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5352. {
  5353. if( ctx->type.dataType.IsIntegerType() ||
  5354. ctx->type.dataType.IsUnsignedType() )
  5355. {
  5356. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5357. {
  5358. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5359. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5360. }
  5361. else
  5362. {
  5363. ConvertToTempVariable(ctx);
  5364. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5365. int offset = AllocateVariable(to, true);
  5366. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5367. ctx->type.SetVariable(to, offset, true);
  5368. }
  5369. }
  5370. else if( ctx->type.dataType.IsFloatType() )
  5371. {
  5372. ConvertToTempVariable(ctx);
  5373. ctx->bc.InstrSHORT(asBC_fTOu, (short)ctx->type.stackOffset);
  5374. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5375. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5376. if( convType != asIC_EXPLICIT_VAL_CAST )
  5377. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5378. }
  5379. else if( ctx->type.dataType.IsDoubleType() )
  5380. {
  5381. ConvertToTempVariable(ctx);
  5382. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5383. int offset = AllocateVariable(to, true);
  5384. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5385. ctx->type.SetVariable(to, offset, true);
  5386. if( convType != asIC_EXPLICIT_VAL_CAST )
  5387. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5388. }
  5389. // Convert to smaller integer if necessary
  5390. s = to.GetSizeInMemoryBytes();
  5391. if( s < 4 )
  5392. {
  5393. ConvertToTempVariable(ctx);
  5394. if( s == 1 )
  5395. ctx->bc.InstrSHORT(asBC_iTOb, (short)ctx->type.stackOffset);
  5396. else if( s == 2 )
  5397. ctx->bc.InstrSHORT(asBC_iTOw, (short)ctx->type.stackOffset);
  5398. }
  5399. }
  5400. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5401. {
  5402. if( ctx->type.dataType.IsIntegerType() ||
  5403. ctx->type.dataType.IsUnsignedType() )
  5404. {
  5405. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5406. {
  5407. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5408. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5409. }
  5410. else
  5411. {
  5412. ConvertToTempVariable(ctx);
  5413. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5414. int offset = AllocateVariable(to, true);
  5415. if( ctx->type.dataType.IsUnsignedType() )
  5416. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5417. else
  5418. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5419. ctx->type.SetVariable(to, offset, true);
  5420. }
  5421. }
  5422. else if( ctx->type.dataType.IsFloatType() )
  5423. {
  5424. ConvertToTempVariable(ctx);
  5425. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5426. int offset = AllocateVariable(to, true);
  5427. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5428. ctx->type.SetVariable(to, offset, true);
  5429. if( convType != asIC_EXPLICIT_VAL_CAST )
  5430. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5431. }
  5432. else if( ctx->type.dataType.IsDoubleType() )
  5433. {
  5434. ConvertToTempVariable(ctx);
  5435. ctx->bc.InstrSHORT(asBC_dTOu64, (short)ctx->type.stackOffset);
  5436. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5437. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5438. if( convType != asIC_EXPLICIT_VAL_CAST )
  5439. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5440. }
  5441. }
  5442. else if( to.IsFloatType() )
  5443. {
  5444. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5445. {
  5446. ConvertToTempVariable(ctx);
  5447. ctx->bc.InstrSHORT(asBC_iTOf, (short)ctx->type.stackOffset);
  5448. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5449. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5450. }
  5451. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5452. {
  5453. ConvertToTempVariable(ctx);
  5454. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5455. int offset = AllocateVariable(to, true);
  5456. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5457. ctx->type.SetVariable(to, offset, true);
  5458. }
  5459. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5460. {
  5461. ConvertToTempVariable(ctx);
  5462. ctx->bc.InstrSHORT(asBC_uTOf, (short)ctx->type.stackOffset);
  5463. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5464. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5465. }
  5466. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5467. {
  5468. ConvertToTempVariable(ctx);
  5469. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5470. int offset = AllocateVariable(to, true);
  5471. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5472. ctx->type.SetVariable(to, offset, true);
  5473. }
  5474. else if( ctx->type.dataType.IsDoubleType() )
  5475. {
  5476. ConvertToTempVariable(ctx);
  5477. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5478. int offset = AllocateVariable(to, true);
  5479. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5480. ctx->type.SetVariable(to, offset, true);
  5481. }
  5482. }
  5483. else if( to.IsDoubleType() )
  5484. {
  5485. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5486. {
  5487. ConvertToTempVariable(ctx);
  5488. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5489. int offset = AllocateVariable(to, true);
  5490. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5491. ctx->type.SetVariable(to, offset, true);
  5492. }
  5493. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5494. {
  5495. ConvertToTempVariable(ctx);
  5496. ctx->bc.InstrSHORT(asBC_i64TOd, (short)ctx->type.stackOffset);
  5497. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5498. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5499. }
  5500. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5501. {
  5502. ConvertToTempVariable(ctx);
  5503. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5504. int offset = AllocateVariable(to, true);
  5505. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5506. ctx->type.SetVariable(to, offset, true);
  5507. }
  5508. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5509. {
  5510. ConvertToTempVariable(ctx);
  5511. ctx->bc.InstrSHORT(asBC_u64TOd, (short)ctx->type.stackOffset);
  5512. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5513. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5514. }
  5515. else if( ctx->type.dataType.IsFloatType() )
  5516. {
  5517. ConvertToTempVariable(ctx);
  5518. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5519. int offset = AllocateVariable(to, true);
  5520. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5521. ctx->type.SetVariable(to, offset, true);
  5522. }
  5523. }
  5524. }
  5525. else
  5526. {
  5527. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5528. to.IsFloatType() || to.IsDoubleType() ||
  5529. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5530. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5531. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5532. {
  5533. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5534. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5535. }
  5536. }
  5537. // Primitive types on the stack, can be const or non-const
  5538. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5539. return cost;
  5540. }
  5541. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5542. {
  5543. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5544. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5545. // Check that the lambda has the correct amount of arguments
  5546. asUINT count = 0;
  5547. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5548. while( argNode->nodeType != snStatementBlock )
  5549. {
  5550. // Check if the specified parameter types match the funcdef
  5551. if (argNode->nodeType == snDataType)
  5552. {
  5553. asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType);
  5554. asETypeModifiers inOutFlag;
  5555. dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
  5556. if (count >= funcDef->parameterTypes.GetLength() ||
  5557. funcDef->parameterTypes[count] != dt ||
  5558. funcDef->inOutFlags[count] != inOutFlag)
  5559. return asCC_NO_CONV;
  5560. argNode = argNode->next;
  5561. }
  5562. if( argNode->nodeType == snIdentifier )
  5563. count++;
  5564. argNode = argNode->next;
  5565. }
  5566. if (funcDef->parameterTypes.GetLength() != count)
  5567. return asCC_NO_CONV;
  5568. asASSERT(argNode->nodeType == snStatementBlock);
  5569. // The Lambda can be used as this funcdef
  5570. ctx->type.dataType = to;
  5571. if( generateCode )
  5572. {
  5573. // Build a unique name for the anonymous function
  5574. asCString name;
  5575. if( m_globalVar )
  5576. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5577. else
  5578. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5579. // Register the lambda with the builder for later compilation
  5580. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace, outFunc->IsShared());
  5581. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5582. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5583. // Clear the expression node as it is no longer valid
  5584. ctx->exprNode = 0;
  5585. }
  5586. return asCC_CONST_CONV;
  5587. }
  5588. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5589. {
  5590. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5591. ctx->type.dataType.IsNullHandle() ||
  5592. ctx->IsAnonymousInitList() );
  5593. if( to.IsFuncdef() && ctx->IsLambda() )
  5594. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5595. if (ctx->IsAnonymousInitList())
  5596. {
  5597. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5598. {
  5599. if (generateCode)
  5600. CompileAnonymousInitList(ctx->exprNode, ctx, to);
  5601. else
  5602. ctx->type.dataType = to;
  5603. }
  5604. return asCC_NO_CONV;
  5605. }
  5606. // No conversion from void to any other type
  5607. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5608. return asCC_NO_CONV;
  5609. // No conversion from class method to any type (it requires delegate)
  5610. if( ctx->IsClassMethod() )
  5611. return asCC_NO_CONV;
  5612. // Do we want a var type?
  5613. if( to.GetTokenType() == ttQuestion )
  5614. {
  5615. // Any type can be converted to a var type, but only when not generating code
  5616. asASSERT( !generateCode );
  5617. ctx->type.dataType = to;
  5618. return asCC_VARIABLE_CONV;
  5619. }
  5620. // Do we want a primitive?
  5621. else if( to.IsPrimitive() )
  5622. {
  5623. if( !ctx->type.dataType.IsPrimitive() )
  5624. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5625. else
  5626. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5627. }
  5628. else // The target is a complex type
  5629. {
  5630. if( ctx->type.dataType.IsPrimitive() )
  5631. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5632. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5633. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5634. }
  5635. return asCC_NO_CONV;
  5636. }
  5637. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5638. {
  5639. if( ctx->type.isExplicitHandle )
  5640. {
  5641. // An explicit handle cannot be converted to a primitive
  5642. if( convType != asIC_IMPLICIT_CONV && node )
  5643. {
  5644. asCString str;
  5645. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5646. Error(str, node);
  5647. }
  5648. return asCC_NO_CONV;
  5649. }
  5650. // Find matching value cast behaviours
  5651. // Here we're only interested in those that convert the type to a primitive type
  5652. asCArray<int> funcs;
  5653. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5654. if( ot == 0 )
  5655. {
  5656. if( convType != asIC_IMPLICIT_CONV && node )
  5657. {
  5658. asCString str;
  5659. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5660. Error(str, node);
  5661. }
  5662. return asCC_NO_CONV;
  5663. }
  5664. if( convType == asIC_EXPLICIT_VAL_CAST )
  5665. {
  5666. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5667. {
  5668. // accept both implicit and explicit cast
  5669. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5670. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5671. mthd->parameterTypes.GetLength() == 0 &&
  5672. mthd->returnType.IsPrimitive() )
  5673. funcs.PushLast(ot->methods[n]);
  5674. }
  5675. }
  5676. else
  5677. {
  5678. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5679. {
  5680. // accept only implicit cast
  5681. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5682. if( mthd->name == "opImplConv" &&
  5683. mthd->parameterTypes.GetLength() == 0 &&
  5684. mthd->returnType.IsPrimitive() )
  5685. funcs.PushLast(ot->methods[n]);
  5686. }
  5687. }
  5688. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5689. int funcId = 0;
  5690. if( to.IsMathType() )
  5691. {
  5692. // This matrix describes the priorities of the types to search for, for each target type
  5693. // The first column is the target type, the priorities goes from left to right
  5694. eTokenType matchMtx[10][10] =
  5695. {
  5696. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5697. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5698. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5699. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5700. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5701. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5702. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5703. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5704. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5705. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5706. };
  5707. // Which row to use?
  5708. eTokenType *row = 0;
  5709. for( unsigned int type = 0; type < 10; type++ )
  5710. {
  5711. if( to.GetTokenType() == matchMtx[type][0] )
  5712. {
  5713. row = &matchMtx[type][0];
  5714. break;
  5715. }
  5716. }
  5717. // Find the best matching cast operator
  5718. if( row )
  5719. {
  5720. asCDataType target(to);
  5721. // Priority goes from left to right in the matrix
  5722. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5723. {
  5724. target.SetTokenType(row[attempt]);
  5725. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5726. {
  5727. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5728. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5729. {
  5730. funcId = funcs[n];
  5731. break;
  5732. }
  5733. }
  5734. }
  5735. }
  5736. }
  5737. else
  5738. {
  5739. // Only accept the exact conversion for non-math types
  5740. // Find the matching cast operator
  5741. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5742. {
  5743. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5744. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5745. {
  5746. funcId = funcs[n];
  5747. break;
  5748. }
  5749. }
  5750. }
  5751. // Did we find a suitable function?
  5752. if( funcId != 0 )
  5753. {
  5754. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5755. if( generateCode )
  5756. {
  5757. Dereference(ctx, true);
  5758. PerformFunctionCall(funcId, ctx);
  5759. }
  5760. else
  5761. ctx->type.Set(descr->returnType);
  5762. // Allow one more implicit conversion to another primitive type
  5763. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5764. }
  5765. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5766. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5767. funcs.SetLength(0);
  5768. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5769. {
  5770. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5771. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5772. func->name == "opImplConv" )
  5773. {
  5774. // Does the operator take the ?&out parameter?
  5775. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5776. func->parameterTypes.GetLength() != 1 ||
  5777. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5778. func->inOutFlags[0] != asTM_OUTREF )
  5779. continue;
  5780. funcs.PushLast(ot->methods[n]);
  5781. }
  5782. }
  5783. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5784. // If there are multiple valid value casts, then we must choose the most appropriate one
  5785. if (funcs.GetLength() > 1)
  5786. {
  5787. // This should only happen in case of explicit value cast and
  5788. // the application has registered both opImplConv and opConv
  5789. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5790. asASSERT(funcs.GetLength() == 2);
  5791. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5792. {
  5793. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5794. if (func->name == "opImplConv")
  5795. {
  5796. funcs.RemoveIndex(n);
  5797. n--;
  5798. }
  5799. }
  5800. }
  5801. if( funcs.GetLength() == 1 )
  5802. {
  5803. if( generateCode )
  5804. {
  5805. // Allocate a temporary variable of the requested type
  5806. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5807. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5808. // Pass the reference of that variable to the function as output parameter
  5809. asCDataType toRef(to);
  5810. toRef.MakeReference(true);
  5811. toRef.MakeReadOnly(false);
  5812. asCArray<asCExprContext *> args;
  5813. asCExprContext arg(engine);
  5814. // Don't mark the variable as temporary, so it won't be freed too early
  5815. arg.type.SetVariable(toRef, stackOffset, false);
  5816. arg.type.isLValue = true;
  5817. arg.exprNode = node;
  5818. args.PushLast(&arg);
  5819. // Call the behaviour method
  5820. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5821. // Use the reference to the variable as the result of the expression
  5822. // Now we can mark the variable as temporary
  5823. toRef.MakeReference(false);
  5824. ctx->type.SetVariable(toRef, stackOffset, true);
  5825. }
  5826. else
  5827. ctx->type.Set(to);
  5828. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5829. }
  5830. if( convType != asIC_IMPLICIT_CONV && node )
  5831. {
  5832. asCString str;
  5833. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5834. Error(str, node);
  5835. }
  5836. return asCC_NO_CONV;
  5837. }
  5838. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5839. {
  5840. // Convert null to any object type handle, but not to a non-handle type
  5841. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5842. {
  5843. if( to.IsObjectHandle() )
  5844. {
  5845. ctx->type.dataType = to;
  5846. return asCC_REF_CONV;
  5847. }
  5848. return asCC_NO_CONV;
  5849. }
  5850. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5851. // First attempt to convert the base type without instantiating another instance
  5852. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5853. {
  5854. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5855. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5856. {
  5857. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5858. return asCC_REF_CONV;
  5859. }
  5860. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5861. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5862. {
  5863. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5864. return asCC_REF_CONV;
  5865. }
  5866. // If the types are not equal yet, then we may still be able to find a reference cast
  5867. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5868. {
  5869. // We may still be able to find an implicit ref cast behaviour
  5870. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5871. // Was the conversion done?
  5872. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5873. return asCC_REF_CONV;
  5874. }
  5875. }
  5876. // Convert matching function types
  5877. if( to.IsFuncdef() )
  5878. {
  5879. // If the input expression is already a funcdef, check if it can be converted
  5880. if( ctx->type.dataType.IsFuncdef() &&
  5881. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5882. {
  5883. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5884. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5885. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5886. {
  5887. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5888. return asCC_REF_CONV;
  5889. }
  5890. }
  5891. // If the input expression is a deferred function ref, check if there is a matching func
  5892. if( ctx->methodName != "" )
  5893. {
  5894. // Determine the namespace
  5895. asSNameSpace *ns = 0;
  5896. asCString name = "";
  5897. int pos = ctx->methodName.FindLast("::");
  5898. if( pos >= 0 )
  5899. {
  5900. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5901. // Trim off the last ::
  5902. if( nsName.GetLength() > 2 )
  5903. nsName.SetLength(nsName.GetLength()-2);
  5904. ns = DetermineNameSpace(nsName);
  5905. name = ctx->methodName.SubString(pos+2);
  5906. }
  5907. else
  5908. {
  5909. DetermineNameSpace("");
  5910. name = ctx->methodName;
  5911. }
  5912. asCArray<int> funcs;
  5913. if( ns )
  5914. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5915. // Check if any of the functions have perfect match
  5916. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5917. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5918. {
  5919. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5920. if( toFunc->IsSignatureExceptNameEqual(func) )
  5921. {
  5922. if( generateCode )
  5923. {
  5924. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5925. // Make sure the identified function is shared if we're compiling a shared function
  5926. if( !func->IsShared() && outFunc->IsShared() )
  5927. {
  5928. asCString msg;
  5929. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5930. Error(msg, node);
  5931. }
  5932. }
  5933. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5934. return asCC_REF_CONV;
  5935. }
  5936. }
  5937. }
  5938. }
  5939. return asCC_NO_CONV;
  5940. }
  5941. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5942. {
  5943. asUINT cost = asCC_NO_CONV;
  5944. // If the base type is still different, and we are allowed to instance
  5945. // another object then we can try an implicit value cast
  5946. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5947. {
  5948. // TODO: Implement support for implicit constructor/factory
  5949. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5950. if( ot == 0 )
  5951. return cost;
  5952. asCArray<int> funcs;
  5953. if( convType == asIC_EXPLICIT_VAL_CAST )
  5954. {
  5955. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5956. {
  5957. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5958. // accept both implicit and explicit cast
  5959. if( (func->name == "opConv" ||
  5960. func->name == "opImplConv") &&
  5961. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5962. func->parameterTypes.GetLength() == 0 )
  5963. funcs.PushLast(ot->methods[n]);
  5964. }
  5965. }
  5966. else
  5967. {
  5968. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5969. {
  5970. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5971. // accept only implicit cast
  5972. if( func->name == "opImplConv" &&
  5973. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5974. func->parameterTypes.GetLength() == 0 )
  5975. funcs.PushLast(ot->methods[n]);
  5976. }
  5977. }
  5978. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5979. // If there are multiple valid value casts, then we must choose the most appropriate one
  5980. if (funcs.GetLength() > 1)
  5981. {
  5982. // This should only happen in case of explicit value cast and
  5983. // the application has registered both opImplConv and opConv
  5984. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5985. asASSERT(funcs.GetLength() == 2);
  5986. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5987. {
  5988. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5989. if (func->name == "opImplConv")
  5990. {
  5991. funcs.RemoveIndex(n);
  5992. n--;
  5993. }
  5994. }
  5995. }
  5996. if( funcs.GetLength() == 1 )
  5997. {
  5998. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5999. if( generateCode )
  6000. {
  6001. Dereference(ctx, true);
  6002. bool useVariable = false;
  6003. int stackOffset = 0;
  6004. if( f->DoesReturnOnStack() )
  6005. {
  6006. useVariable = true;
  6007. stackOffset = AllocateVariable(f->returnType, true);
  6008. // Push the pointer to the pre-allocated space for the return value
  6009. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  6010. // The object pointer is already on the stack, but should be the top
  6011. // one, so we need to swap the pointers in order to get the correct
  6012. ctx->bc.Instr(asBC_SwapPtr);
  6013. }
  6014. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  6015. }
  6016. else
  6017. ctx->type.Set(f->returnType);
  6018. cost = asCC_TO_OBJECT_CONV;
  6019. }
  6020. else
  6021. {
  6022. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  6023. // Look for a value cast with variable type
  6024. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6025. {
  6026. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6027. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  6028. func->name == "opImplConv" )
  6029. {
  6030. // Does the operator take the ?&out parameter?
  6031. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  6032. func->parameterTypes.GetLength() != 1 ||
  6033. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  6034. func->inOutFlags[0] != asTM_OUTREF )
  6035. continue;
  6036. funcs.PushLast(ot->methods[n]);
  6037. }
  6038. }
  6039. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  6040. // If there are multiple valid value casts, then we must choose the most appropriate one
  6041. if (funcs.GetLength() > 1)
  6042. {
  6043. // This should only happen in case of explicit value cast and
  6044. // the application has registered both opImplConv and opConv
  6045. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  6046. asASSERT(funcs.GetLength() == 2);
  6047. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6048. {
  6049. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  6050. if (func->name == "opImplConv")
  6051. {
  6052. funcs.RemoveIndex(n);
  6053. n--;
  6054. }
  6055. }
  6056. }
  6057. if( funcs.GetLength() == 1 )
  6058. {
  6059. cost = asCC_TO_OBJECT_CONV;
  6060. if( generateCode )
  6061. {
  6062. // Allocate a temporary variable of the requested type
  6063. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  6064. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  6065. // Pass the reference of that variable to the function as output parameter
  6066. asCDataType toRef(to);
  6067. toRef.MakeReference(false);
  6068. asCExprContext arg(engine);
  6069. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6070. // If this an object on the heap, the pointer must be dereferenced
  6071. if( IsVariableOnHeap(stackOffset) )
  6072. arg.bc.Instr(asBC_RDSPtr);
  6073. // Don't mark the variable as temporary, so it won't be freed too early
  6074. arg.type.SetVariable(toRef, stackOffset, false);
  6075. arg.type.isLValue = true;
  6076. arg.exprNode = node;
  6077. // Mark the argument as clean, so that MakeFunctionCall knows it
  6078. // doesn't have to make a copy of it in order to protect the value
  6079. arg.isCleanArg = true;
  6080. // Call the behaviour method
  6081. asCArray<asCExprContext *> args;
  6082. args.PushLast(&arg);
  6083. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  6084. // Use the reference to the variable as the result of the expression
  6085. // Now we can mark the variable as temporary
  6086. ctx->type.SetVariable(toRef, stackOffset, true);
  6087. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6088. }
  6089. else
  6090. {
  6091. // All casts are legal
  6092. ctx->type.Set(to);
  6093. }
  6094. }
  6095. else if( CastToObjectType(to.GetTypeInfo()) )
  6096. {
  6097. // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type
  6098. if( to.GetTypeInfo()->flags & asOBJ_REF )
  6099. funcs = CastToObjectType(to.GetTypeInfo())->beh.factories;
  6100. else
  6101. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6102. // If not explicit cast, remove any explicit conversion constructors
  6103. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6104. {
  6105. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6106. if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) )
  6107. funcs.RemoveIndex(n--);
  6108. }
  6109. asCArray<asCExprContext *> args;
  6110. args.PushLast(ctx);
  6111. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6112. // Did we find a matching constructor?
  6113. if (funcs.GetLength() == 1)
  6114. {
  6115. if (generateCode)
  6116. {
  6117. // TODO: This should really reuse the code from CompileConstructCall
  6118. // Allocate the new object
  6119. asCExprValue tempObj;
  6120. asCExprContext e(engine);
  6121. bool onHeap = false;
  6122. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6123. {
  6124. tempObj.dataType = to;
  6125. tempObj.dataType.MakeReference(false);
  6126. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6127. tempObj.dataType.MakeReference(true);
  6128. tempObj.isTemporary = true;
  6129. tempObj.isVariable = true;
  6130. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6131. // Push the address of the object on the stack
  6132. if (onHeap)
  6133. e.bc.InstrSHORT(asBC_VAR, (short)tempObj.stackOffset);
  6134. }
  6135. PrepareFunctionCall(funcs[0], &e.bc, args);
  6136. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6137. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6138. {
  6139. // If the object is allocated on the stack, then call the constructor as a normal function
  6140. if (onHeap)
  6141. {
  6142. int offset = 0;
  6143. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6144. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6145. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6146. }
  6147. else
  6148. e.bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6149. }
  6150. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6151. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6152. {
  6153. // Add tag that the object has been initialized
  6154. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6155. // The constructor doesn't return anything,
  6156. // so we have to manually inform the type of
  6157. // the return value
  6158. e.type = tempObj;
  6159. if (!onHeap)
  6160. e.type.dataType.MakeReference(false);
  6161. // Push the address of the object on the stack again
  6162. e.bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6163. }
  6164. MergeExprBytecodeAndType(ctx, &e);
  6165. }
  6166. else
  6167. {
  6168. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6169. }
  6170. }
  6171. }
  6172. }
  6173. }
  6174. return cost;
  6175. }
  6176. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  6177. {
  6178. // First try a ref cast
  6179. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  6180. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  6181. // construct the object through any of the available constructors (except those marked as explicit)
  6182. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6183. {
  6184. asCArray<int> funcs;
  6185. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6186. // Don't allow use of explicit constructors/factories in implicit conversions
  6187. if (convType == asIC_IMPLICIT_CONV)
  6188. {
  6189. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6190. {
  6191. asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]);
  6192. if (desc->IsExplicit())
  6193. funcs.RemoveIndex(n--);
  6194. }
  6195. }
  6196. asCArray<asCExprContext *> args;
  6197. args.PushLast(ctx);
  6198. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6199. // Did we find a matching constructor?
  6200. if( funcs.GetLength() == 1 )
  6201. {
  6202. if( generateCode )
  6203. {
  6204. // If the ASHANDLE receives a variable type parameter, then we need to
  6205. // make sure the expression is treated as a handle and not as a value
  6206. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  6207. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  6208. {
  6209. if( !ctx->type.isExplicitHandle )
  6210. {
  6211. asCDataType toHandle = ctx->type.dataType;
  6212. toHandle.MakeHandle(true);
  6213. toHandle.MakeReference(true);
  6214. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  6215. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  6216. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6217. }
  6218. ctx->type.isExplicitHandle = true;
  6219. }
  6220. // TODO: This should really reuse the code from CompileConstructCall
  6221. // Allocate the new object
  6222. asCExprValue tempObj;
  6223. tempObj.dataType = to;
  6224. tempObj.dataType.MakeReference(false);
  6225. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6226. tempObj.dataType.MakeReference(true);
  6227. tempObj.isTemporary = true;
  6228. tempObj.isVariable = true;
  6229. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6230. // Push the address of the object on the stack
  6231. asCExprContext e(engine);
  6232. if( onHeap )
  6233. e.bc.InstrSHORT(asBC_VAR, (short)tempObj.stackOffset);
  6234. PrepareFunctionCall(funcs[0], &e.bc, args);
  6235. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6236. // If the object is allocated on the stack, then call the constructor as a normal function
  6237. if( onHeap )
  6238. {
  6239. int offset = 0;
  6240. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6241. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6242. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6243. }
  6244. else
  6245. e.bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6246. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6247. // Add tag that the object has been initialized
  6248. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6249. // The constructor doesn't return anything,
  6250. // so we have to manually inform the type of
  6251. // the return value
  6252. e.type = tempObj;
  6253. if( !onHeap )
  6254. e.type.dataType.MakeReference(false);
  6255. // Push the address of the object on the stack again
  6256. e.bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6257. MergeExprBytecodeAndType(ctx, &e);
  6258. }
  6259. else
  6260. {
  6261. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6262. }
  6263. }
  6264. }
  6265. // If the base type is still different, and we are allowed to instance
  6266. // another object then we can try an implicit value cast
  6267. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6268. {
  6269. // Attempt implicit value cast
  6270. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  6271. }
  6272. // If we still haven't converted the base type to the correct type, then there is
  6273. // no need to continue as it is not possible to do the conversion
  6274. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  6275. return asCC_NO_CONV;
  6276. if( to.IsObjectHandle() )
  6277. {
  6278. // There is no extra cost in converting to a handle
  6279. // reference to handle -> handle
  6280. // reference -> handle
  6281. // object -> handle
  6282. // handle -> reference to handle
  6283. // reference -> reference to handle
  6284. // object -> reference to handle
  6285. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
  6286. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
  6287. {
  6288. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6289. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6290. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6291. {
  6292. if (generateCode)
  6293. PrepareTemporaryVariable(node, ctx);
  6294. else
  6295. {
  6296. ctx->type.dataType.MakeReadOnly(false);
  6297. ctx->type.isConstant = false;
  6298. }
  6299. // Add the cost for the copy
  6300. cost += asCC_TO_OBJECT_CONV;
  6301. }
  6302. else if( convType != asIC_IMPLICIT_CONV )
  6303. {
  6304. asASSERT(node);
  6305. asCString str;
  6306. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  6307. Error(str, node);
  6308. }
  6309. }
  6310. if( !ctx->type.dataType.IsObjectHandle() )
  6311. {
  6312. // An object type can be directly converted to a handle of the
  6313. // same type by doing a ref copy to a new variable
  6314. if( ctx->type.dataType.SupportHandles() )
  6315. {
  6316. asCDataType dt = ctx->type.dataType;
  6317. dt.MakeHandle(true);
  6318. dt.MakeReference(false);
  6319. if( generateCode )
  6320. {
  6321. // If the expression is already a local variable, then it is not
  6322. // necessary to do a ref copy, as the ref objects on the stack are
  6323. // really handles, only the handles cannot be modified.
  6324. if( ctx->type.isVariable )
  6325. {
  6326. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  6327. ctx->type.dataType.MakeReadOnly(false);
  6328. ctx->type.dataType.MakeHandle(true);
  6329. ctx->type.dataType.MakeReadOnly(true);
  6330. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  6331. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6332. {
  6333. ctx->bc.Instr(asBC_PopPtr);
  6334. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  6335. ctx->type.dataType.MakeReference(true);
  6336. }
  6337. else if( ctx->type.dataType.IsReference() )
  6338. {
  6339. ctx->bc.Instr(asBC_RDSPtr);
  6340. ctx->type.dataType.MakeReference(false);
  6341. }
  6342. }
  6343. else
  6344. {
  6345. int offset = AllocateVariable(dt, true);
  6346. if( ctx->type.dataType.IsReference() )
  6347. ctx->bc.Instr(asBC_RDSPtr);
  6348. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6349. if (dt.IsFuncdef())
  6350. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  6351. else
  6352. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  6353. ctx->bc.Instr(asBC_PopPtr);
  6354. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6355. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6356. if( to.IsReference() )
  6357. dt.MakeReference(true);
  6358. else
  6359. ctx->bc.Instr(asBC_RDSPtr);
  6360. ctx->type.SetVariable(dt, offset, true);
  6361. }
  6362. }
  6363. else
  6364. ctx->type.dataType = dt;
  6365. // When this conversion is done the expression is no longer an lvalue
  6366. ctx->type.isLValue = false;
  6367. }
  6368. }
  6369. if( ctx->type.dataType.IsObjectHandle() )
  6370. {
  6371. // A handle to non-const can be converted to a
  6372. // handle to const, but not the other way
  6373. if( to.IsHandleToConst() )
  6374. ctx->type.dataType.MakeHandleToConst(true);
  6375. // A const handle can be converted to a non-const
  6376. // handle and vice versa as the handle is just a value
  6377. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6378. }
  6379. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6380. {
  6381. if( generateCode )
  6382. {
  6383. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6384. // If the input type is a handle, then a simple ref copy is enough
  6385. bool isExplicitHandle = ctx->type.isExplicitHandle;
  6386. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  6387. // If the input type is read-only we'll need to temporarily
  6388. // remove this constness, otherwise the assignment will fail
  6389. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6390. ctx->type.dataType.MakeReadOnly(false);
  6391. // If the object already is a temporary variable, then the copy
  6392. // doesn't have to be made as it is already a unique object
  6393. PrepareTemporaryVariable(node, ctx);
  6394. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6395. ctx->type.isExplicitHandle = isExplicitHandle;
  6396. }
  6397. // A non-reference can be converted to a reference,
  6398. // by putting the value in a temporary variable
  6399. ctx->type.dataType.MakeReference(true);
  6400. // Since it is a new temporary variable it doesn't have to be const
  6401. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6402. }
  6403. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  6404. {
  6405. Dereference(ctx, generateCode);
  6406. }
  6407. }
  6408. else // if( !to.IsObjectHandle() )
  6409. {
  6410. if( !to.IsReference() )
  6411. {
  6412. // reference to handle -> object
  6413. // handle -> object
  6414. // reference -> object
  6415. // An implicit handle can be converted to an object by adding a check for null pointer
  6416. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6417. {
  6418. if( generateCode )
  6419. {
  6420. if( ctx->type.dataType.IsReference() )
  6421. {
  6422. // The pointer on the stack refers to the handle
  6423. ctx->bc.Instr(asBC_ChkRefS);
  6424. }
  6425. else
  6426. {
  6427. // The pointer on the stack refers to the object
  6428. ctx->bc.Instr(asBC_CHKREF);
  6429. }
  6430. }
  6431. ctx->type.dataType.MakeHandle(false);
  6432. }
  6433. // A const object can be converted to a non-const object through a copy
  6434. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  6435. allowObjectConstruct )
  6436. {
  6437. // Does the object type allow a copy to be made?
  6438. if( ctx->type.dataType.CanBeCopied() )
  6439. {
  6440. if( generateCode )
  6441. {
  6442. // Make a temporary object with the copy
  6443. PrepareTemporaryVariable(node, ctx);
  6444. }
  6445. // In case the object was already in a temporary variable, then the function
  6446. // didn't really do anything so we need to remove the constness here
  6447. ctx->type.dataType.MakeReadOnly(false);
  6448. // Add the cost for the copy
  6449. cost += asCC_TO_OBJECT_CONV;
  6450. }
  6451. }
  6452. if( ctx->type.dataType.IsReference() )
  6453. {
  6454. // This may look strange, but a value type allocated on the stack is already
  6455. // correct, so nothing should be done other than remove the mark as reference.
  6456. // For types allocated on the heap, it is necessary to dereference the pointer
  6457. // that is currently on the stack
  6458. if( IsVariableOnHeap(ctx->type.stackOffset) )
  6459. Dereference(ctx, generateCode);
  6460. else
  6461. ctx->type.dataType.MakeReference(false);
  6462. }
  6463. // A non-const object can be converted to a const object directly
  6464. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6465. {
  6466. ctx->type.dataType.MakeReadOnly(true);
  6467. }
  6468. }
  6469. else // if( to.IsReference() )
  6470. {
  6471. // reference to handle -> reference
  6472. // handle -> reference
  6473. // object -> reference
  6474. if( ctx->type.dataType.IsReference() )
  6475. {
  6476. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6477. {
  6478. // ASHANDLE objects are really value types, so explicit handle can be removed
  6479. ctx->type.isExplicitHandle = false;
  6480. ctx->type.dataType.MakeHandle(false);
  6481. }
  6482. // A reference to a handle can be converted to a reference to an object
  6483. // by first reading the address, then verifying that it is not null
  6484. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6485. {
  6486. ctx->type.dataType.MakeHandle(false);
  6487. if( generateCode )
  6488. ctx->bc.Instr(asBC_ChkRefS);
  6489. }
  6490. // A reference to a non-const can be converted to a reference to a const
  6491. if( to.IsReadOnly() )
  6492. ctx->type.dataType.MakeReadOnly(true);
  6493. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6494. {
  6495. // A reference to a const can be converted to a reference to a
  6496. // non-const by copying the object to a temporary variable
  6497. ctx->type.dataType.MakeReadOnly(false);
  6498. if( generateCode )
  6499. {
  6500. // If the object already is a temporary variable, then the copy
  6501. // doesn't have to be made as it is already a unique object
  6502. PrepareTemporaryVariable(node, ctx);
  6503. }
  6504. // Add the cost for the copy
  6505. cost += asCC_TO_OBJECT_CONV;
  6506. }
  6507. }
  6508. else // if( !ctx->type.dataType.IsReference() )
  6509. {
  6510. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6511. if( ctx->type.dataType.IsObjectHandle() )
  6512. {
  6513. bool readOnly = false;
  6514. if( ctx->type.dataType.IsHandleToConst() )
  6515. readOnly = true;
  6516. if( generateCode )
  6517. {
  6518. if( ctx->type.isVariable )
  6519. ctx->bc.InstrSHORT(asBC_ChkNullV, (short)ctx->type.stackOffset);
  6520. else
  6521. ctx->bc.Instr(asBC_CHKREF);
  6522. }
  6523. ctx->type.dataType.MakeHandle(false);
  6524. ctx->type.dataType.MakeReference(true);
  6525. // Make sure a handle to const isn't converted to non-const reference
  6526. if( readOnly )
  6527. ctx->type.dataType.MakeReadOnly(true);
  6528. }
  6529. else
  6530. {
  6531. // A value type allocated on the stack is differentiated
  6532. // by it not being a reference. But it can be handled as
  6533. // reference by pushing the pointer on the stack
  6534. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6535. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6536. !IsVariableOnHeap(ctx->type.stackOffset) )
  6537. {
  6538. // Actually the pointer is already pushed on the stack in
  6539. // CompileVariableAccess, so we don't need to do anything else
  6540. }
  6541. else if( generateCode )
  6542. {
  6543. // A non-reference can be converted to a reference,
  6544. // by putting the value in a temporary variable
  6545. // If the input type is read-only we'll need to temporarily
  6546. // remove this constness, otherwise the assignment will fail
  6547. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6548. ctx->type.dataType.MakeReadOnly(false);
  6549. // If the object already is a temporary variable, then the copy
  6550. // doesn't have to be made as it is already a unique object
  6551. PrepareTemporaryVariable(node, ctx);
  6552. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6553. // Add the cost for the copy
  6554. cost += asCC_TO_OBJECT_CONV;
  6555. }
  6556. // This may look strange as the conversion was to make the expression a reference
  6557. // but a value type allocated on the stack is a reference even without the type
  6558. // being marked as such.
  6559. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6560. }
  6561. if (to.IsReadOnly())
  6562. {
  6563. // This doesn't cost anything
  6564. ctx->type.dataType.MakeReadOnly(true);
  6565. }
  6566. if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
  6567. {
  6568. // A const object can be converted to a non-const object through a copy
  6569. if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
  6570. {
  6571. ctx->type.dataType.MakeReadOnly(false);
  6572. if (generateCode)
  6573. {
  6574. // Make a temporary copy of the object in order to make it non-const
  6575. PrepareTemporaryVariable(node, ctx);
  6576. }
  6577. // Add the cost for the copy
  6578. cost += asCC_TO_OBJECT_CONV;
  6579. }
  6580. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6581. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6582. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6583. {
  6584. if (generateCode)
  6585. PrepareTemporaryVariable(node, ctx);
  6586. else
  6587. {
  6588. ctx->type.dataType.MakeReadOnly(false);
  6589. ctx->type.isConstant = false;
  6590. }
  6591. // Add the cost for the copy
  6592. cost += asCC_TO_OBJECT_CONV;
  6593. }
  6594. }
  6595. }
  6596. }
  6597. }
  6598. return cost;
  6599. }
  6600. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct)
  6601. {
  6602. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6603. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6604. if( !objType )
  6605. return asCC_NO_CONV;
  6606. asCArray<int> funcs;
  6607. if (objType->flags & asOBJ_VALUE)
  6608. {
  6609. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6610. for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++)
  6611. {
  6612. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6613. if (func->parameterTypes.GetLength() == 1 &&
  6614. func->parameterTypes[0].IsPrimitive() &&
  6615. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6616. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) )
  6617. {
  6618. funcs.PushLast(func->id);
  6619. }
  6620. }
  6621. }
  6622. else if (objType->flags & asOBJ_REF)
  6623. {
  6624. // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference
  6625. for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++)
  6626. {
  6627. asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]];
  6628. if (func->parameterTypes.GetLength() == 1 &&
  6629. func->parameterTypes[0].IsPrimitive() &&
  6630. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6631. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()))
  6632. {
  6633. funcs.PushLast(func->id);
  6634. }
  6635. }
  6636. }
  6637. if( funcs.GetLength() == 0 )
  6638. return asCC_NO_CONV;
  6639. // Check if it is possible to choose a best match
  6640. asCExprContext arg(engine);
  6641. arg.type = ctx->type;
  6642. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6643. asCArray<asCExprContext*> args;
  6644. args.PushLast(&arg);
  6645. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6646. if( funcs.GetLength() != 1 )
  6647. return asCC_NO_CONV;
  6648. if( !generateCode )
  6649. {
  6650. ctx->type.Set(to);
  6651. return cost;
  6652. }
  6653. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6654. // Clear the type of ctx, as the type is moved to the arg
  6655. ctx->type.SetDummy();
  6656. // Value types and script types are allocated through the constructor
  6657. asCExprValue tempObj;
  6658. bool onHeap = false;
  6659. if (!(objType->flags & asOBJ_REF))
  6660. {
  6661. tempObj.dataType = to;
  6662. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6663. tempObj.dataType.MakeReference(true);
  6664. tempObj.isTemporary = true;
  6665. tempObj.isVariable = true;
  6666. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6667. // Push the address of the object on the stack
  6668. if (onHeap)
  6669. ctx->bc.InstrSHORT(asBC_VAR, (short)tempObj.stackOffset);
  6670. }
  6671. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6672. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6673. if( !(objType->flags & asOBJ_REF) )
  6674. {
  6675. // If the object is allocated on the stack, then call the constructor as a normal function
  6676. if( onHeap )
  6677. {
  6678. int offset = 0;
  6679. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6680. for( asUINT n = 0; n < args.GetLength(); n++ )
  6681. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6682. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6683. }
  6684. else
  6685. ctx->bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6686. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6687. // Add tag that the object has been initialized
  6688. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6689. // The constructor doesn't return anything,
  6690. // so we have to manually inform the type of
  6691. // the return value
  6692. ctx->type = tempObj;
  6693. if( !onHeap )
  6694. ctx->type.dataType.MakeReference(false);
  6695. // Push the address of the object on the stack again
  6696. ctx->bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  6697. }
  6698. else
  6699. {
  6700. // Call the factory to create the reference type
  6701. PerformFunctionCall(funcs[0], ctx, false, &args);
  6702. // Make another pass to make sure the result has the correct handle and reference settings
  6703. ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct);
  6704. }
  6705. return cost;
  6706. }
  6707. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6708. {
  6709. asASSERT(from->type.isConstant);
  6710. // TODO: node should be the node of the value that is
  6711. // converted (not the operator that provokes the implicit
  6712. // conversion)
  6713. // If the base type is correct there is no more to do
  6714. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6715. // References cannot be constants
  6716. if( from->type.dataType.IsReference() ) return;
  6717. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6718. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6719. {
  6720. if( from->type.dataType.IsFloatType() ||
  6721. from->type.dataType.IsDoubleType() ||
  6722. from->type.dataType.IsUnsignedType() ||
  6723. from->type.dataType.IsIntegerType() )
  6724. {
  6725. asCDataType targetDt;
  6726. if (to.IsEnumType())
  6727. targetDt = to;
  6728. else
  6729. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6730. // Transform the value
  6731. // Float constants can be implicitly converted to int
  6732. if( from->type.dataType.IsFloatType() )
  6733. {
  6734. float fc = from->type.GetConstantF();
  6735. int ic = int(fc);
  6736. if( float(ic) != fc )
  6737. {
  6738. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6739. }
  6740. from->type.SetConstantDW(targetDt, ic);
  6741. }
  6742. // Double constants can be implicitly converted to int
  6743. else if( from->type.dataType.IsDoubleType() )
  6744. {
  6745. double fc = from->type.GetConstantD();
  6746. int ic = int(fc);
  6747. if( double(ic) != fc )
  6748. {
  6749. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6750. }
  6751. from->type.SetConstantDW(targetDt, ic);
  6752. }
  6753. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6754. {
  6755. // Verify that it is possible to convert to signed without getting negative
  6756. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6757. int(from->type.GetConstantDW()) < 0 &&
  6758. convType != asIC_EXPLICIT_VAL_CAST &&
  6759. node != 0 )
  6760. Warning(TXT_CHANGE_SIGN, node);
  6761. // Convert to 32bit
  6762. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6763. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6764. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6765. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6766. else
  6767. from->type.dataType = targetDt;
  6768. }
  6769. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6770. {
  6771. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6772. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6773. // Convert to 32bit
  6774. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6775. }
  6776. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6777. {
  6778. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6779. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6780. // Convert to 32bit
  6781. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6782. }
  6783. else if (from->type.dataType.IsIntegerType() &&
  6784. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6785. {
  6786. // Convert to 32bit
  6787. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6788. from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
  6789. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6790. from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
  6791. }
  6792. else
  6793. {
  6794. // Only int32 and enums should come here and as these are 32bit
  6795. // already nothing needs to be done except set the target type
  6796. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6797. from->type.dataType.IsEnumType()) &&
  6798. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6799. from->type.dataType = targetDt;
  6800. }
  6801. }
  6802. // Check if a downsize is necessary
  6803. if( to.IsIntegerType() &&
  6804. from->type.dataType.IsIntegerType() &&
  6805. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6806. {
  6807. // Verify if it is possible
  6808. if( to.GetSizeInMemoryBytes() == 1 )
  6809. {
  6810. if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6811. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6812. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
  6813. }
  6814. else if( to.GetSizeInMemoryBytes() == 2 )
  6815. {
  6816. if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6817. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6818. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
  6819. }
  6820. }
  6821. }
  6822. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6823. {
  6824. // Float constants can be implicitly converted to int
  6825. if( from->type.dataType.IsFloatType() )
  6826. {
  6827. float fc = from->type.GetConstantF();
  6828. asINT64 ic = asINT64(fc);
  6829. if( float(ic) != fc )
  6830. {
  6831. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6832. }
  6833. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6834. }
  6835. // Double constants can be implicitly converted to int
  6836. else if( from->type.dataType.IsDoubleType() )
  6837. {
  6838. double fc = from->type.GetConstantD();
  6839. asINT64 ic = asINT64(fc);
  6840. if( double(ic) != fc )
  6841. {
  6842. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6843. }
  6844. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6845. }
  6846. else if( from->type.dataType.IsUnsignedType() )
  6847. {
  6848. // Convert to 64bit
  6849. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6850. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6851. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6852. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6853. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6854. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6855. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6856. {
  6857. if( asINT64(from->type.GetConstantQW()) < 0 )
  6858. {
  6859. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6860. }
  6861. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6862. }
  6863. }
  6864. else if( from->type.dataType.IsIntegerType() )
  6865. {
  6866. // Convert to 64bit
  6867. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6868. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
  6869. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6870. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
  6871. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6872. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6873. }
  6874. }
  6875. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6876. {
  6877. if( from->type.dataType.IsFloatType() )
  6878. {
  6879. float fc = from->type.GetConstantF();
  6880. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6881. // To maintain a consistent behaviour across compilers we convert to int first.
  6882. asUINT uic = asUINT(int(fc));
  6883. if( float(uic) != fc )
  6884. {
  6885. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6886. }
  6887. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6888. // Try once more, in case of a smaller type
  6889. ImplicitConversionConstant(from, to, node, convType);
  6890. }
  6891. else if( from->type.dataType.IsDoubleType() )
  6892. {
  6893. double fc = from->type.GetConstantD();
  6894. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6895. // To maintain a consistent behaviour across compilers we convert to int first.
  6896. asUINT uic = asUINT(int(fc));
  6897. if( double(uic) != fc )
  6898. {
  6899. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6900. }
  6901. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6902. // Try once more, in case of a smaller type
  6903. ImplicitConversionConstant(from, to, node, convType);
  6904. }
  6905. else if( from->type.dataType.IsIntegerType() )
  6906. {
  6907. // Verify that it is possible to convert to unsigned without loosing negative
  6908. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6909. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6910. (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
  6911. (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
  6912. {
  6913. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6914. }
  6915. // Check if any data is lost
  6916. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6917. {
  6918. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6919. }
  6920. // Convert to 32bit
  6921. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6922. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
  6923. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6924. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
  6925. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6926. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6927. else
  6928. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6929. // Try once more, in case of a smaller type
  6930. ImplicitConversionConstant(from, to, node, convType);
  6931. }
  6932. else if( from->type.dataType.IsUnsignedType() &&
  6933. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6934. {
  6935. // Convert to 32bit
  6936. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6937. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6938. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6939. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6940. // Try once more, in case of a smaller type
  6941. ImplicitConversionConstant(from, to, node, convType);
  6942. }
  6943. else if( from->type.dataType.IsUnsignedType() &&
  6944. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6945. {
  6946. // Verify if it is possible
  6947. if( to.GetSizeInMemoryBytes() == 1 )
  6948. {
  6949. if( (from->type.dataType.GetSizeInMemoryBytes() == 2 && asBYTE(from->type.GetConstantW()) != from->type.GetConstantW()) ||
  6950. (from->type.dataType.GetSizeInMemoryBytes() == 4 && asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6951. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asBYTE(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6952. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6953. if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6954. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantW()));
  6955. else if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6956. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6957. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6958. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantQW()));
  6959. }
  6960. else if( to.GetSizeInMemoryBytes() == 2 )
  6961. {
  6962. if( (from->type.dataType.GetSizeInMemoryBytes() == 4 && asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6963. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6964. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6965. if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6966. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6967. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6968. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantQW()));
  6969. }
  6970. else if (to.GetSizeInMemoryBytes() == 4)
  6971. {
  6972. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6973. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6974. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6975. }
  6976. }
  6977. }
  6978. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6979. {
  6980. if( from->type.dataType.IsFloatType() )
  6981. {
  6982. float fc = from->type.GetConstantF();
  6983. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6984. asQWORD uic = asQWORD(asINT64(fc));
  6985. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6986. // MSVC6 doesn't support this conversion
  6987. if( float(uic) != fc )
  6988. {
  6989. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6990. }
  6991. #endif
  6992. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6993. }
  6994. else if( from->type.dataType.IsDoubleType() )
  6995. {
  6996. double fc = from->type.GetConstantD();
  6997. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6998. asQWORD uic = asQWORD(asINT64(fc));
  6999. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  7000. // MSVC6 doesn't support this conversion
  7001. if( double(uic) != fc )
  7002. {
  7003. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7004. }
  7005. #endif
  7006. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  7007. }
  7008. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7009. {
  7010. // Convert to 64bit
  7011. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7012. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
  7013. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7014. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
  7015. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  7016. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  7017. // Verify that it is possible to convert to unsigned without loosing negative
  7018. if( asINT64(from->type.GetConstantQW()) < 0 )
  7019. {
  7020. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  7021. }
  7022. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  7023. }
  7024. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7025. {
  7026. // Verify that it is possible to convert to unsigned without loosing negative
  7027. if( asINT64(from->type.GetConstantQW()) < 0 )
  7028. {
  7029. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  7030. }
  7031. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  7032. }
  7033. else if( from->type.dataType.IsUnsignedType() )
  7034. {
  7035. // Convert to 64bit
  7036. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7037. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  7038. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7039. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  7040. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  7041. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  7042. }
  7043. }
  7044. else if( to.IsFloatType() )
  7045. {
  7046. if( from->type.dataType.IsDoubleType() )
  7047. {
  7048. double ic = from->type.GetConstantD();
  7049. float fc = float(ic);
  7050. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7051. }
  7052. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7053. {
  7054. // Must properly convert value in case the from value is smaller
  7055. int ic;
  7056. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7057. ic = (asINT8)from->type.GetConstantB();
  7058. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7059. ic = (asINT16)from->type.GetConstantW();
  7060. else
  7061. ic = (int)from->type.GetConstantDW();
  7062. float fc = float(ic);
  7063. if( int(fc) != ic )
  7064. {
  7065. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7066. }
  7067. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7068. }
  7069. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7070. {
  7071. float fc = float(asINT64(from->type.GetConstantQW()));
  7072. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7073. {
  7074. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7075. }
  7076. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7077. }
  7078. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7079. {
  7080. // Must properly convert value in case the from value is smaller
  7081. unsigned int uic;
  7082. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7083. uic = from->type.GetConstantB();
  7084. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7085. uic = from->type.GetConstantW();
  7086. else
  7087. uic = from->type.GetConstantDW();
  7088. float fc = float(uic);
  7089. if( (unsigned int)(fc) != uic )
  7090. {
  7091. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7092. }
  7093. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7094. }
  7095. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7096. {
  7097. float fc = float((asINT64)from->type.GetConstantQW());
  7098. if( asQWORD(fc) != from->type.GetConstantQW())
  7099. {
  7100. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7101. }
  7102. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7103. }
  7104. }
  7105. else if( to.IsDoubleType() )
  7106. {
  7107. if( from->type.dataType.IsFloatType() )
  7108. {
  7109. float ic = from->type.GetConstantF();
  7110. double fc = double(ic);
  7111. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7112. }
  7113. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7114. {
  7115. // Must properly convert value in case the from value is smaller
  7116. int ic;
  7117. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7118. ic = (asINT8)from->type.GetConstantB();
  7119. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7120. ic = (asINT16)from->type.GetConstantW();
  7121. else
  7122. ic = (int)from->type.GetConstantDW();
  7123. double fc = double(ic);
  7124. if( int(fc) != ic )
  7125. {
  7126. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7127. }
  7128. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7129. }
  7130. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7131. {
  7132. double fc = double(asINT64(from->type.GetConstantQW()));
  7133. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7134. {
  7135. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7136. }
  7137. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7138. }
  7139. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7140. {
  7141. // Must properly convert value in case the from value is smaller
  7142. unsigned int uic;
  7143. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7144. uic = from->type.GetConstantB();
  7145. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7146. uic = from->type.GetConstantW();
  7147. else
  7148. uic = from->type.GetConstantDW();
  7149. double fc = double(uic);
  7150. if( (unsigned int)(fc) != uic )
  7151. {
  7152. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7153. }
  7154. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7155. }
  7156. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7157. {
  7158. double fc = double((asINT64)from->type.GetConstantQW());
  7159. if( asQWORD(fc) != from->type.GetConstantQW())
  7160. {
  7161. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7162. }
  7163. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7164. }
  7165. }
  7166. }
  7167. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  7168. {
  7169. // Don't allow any operators on expressions that take address of class method
  7170. // If methodName is set but the type is not an object, then it is a global function
  7171. if( lctx->methodName != "" || rctx->IsClassMethod() )
  7172. {
  7173. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  7174. return -1;
  7175. }
  7176. // Implicit handle types should always be treated as handles in assignments
  7177. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  7178. {
  7179. lctx->type.dataType.MakeHandle(true);
  7180. lctx->type.isExplicitHandle = true;
  7181. }
  7182. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  7183. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  7184. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  7185. (!lctx->type.dataType.GetBehaviour() || !lctx->type.dataType.GetBehaviour()->copy))
  7186. lctx->type.isExplicitHandle = true;
  7187. // If the left hand expression is a property accessor, then that should be used
  7188. // to do the assignment instead of the ordinary operator. The exception is when
  7189. // the property accessor is for a handle property, and the operation is a value
  7190. // assignment.
  7191. if( (lctx->property_get || lctx->property_set) &&
  7192. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  7193. {
  7194. if( op != ttAssignment )
  7195. {
  7196. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  7197. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  7198. }
  7199. // It is not allowed to do a handle assignment on a property
  7200. // accessor that doesn't take a handle in the set accessor.
  7201. if( lctx->property_set && lctx->type.isExplicitHandle )
  7202. {
  7203. // set_opIndex has 2 arguments, where as normal setters have only 1
  7204. asCArray<asCDataType>& parameterTypes =
  7205. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  7206. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  7207. {
  7208. // Process the property to free the memory
  7209. ProcessPropertySetAccessor(lctx, rctx, opNode);
  7210. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  7211. return -1;
  7212. }
  7213. }
  7214. MergeExprBytecodeAndType(ctx, lctx);
  7215. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  7216. }
  7217. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7218. {
  7219. // Get the handle to the object that will be used for the value assignment
  7220. if( ProcessPropertyGetAccessor(lctx, opNode) < 0 )
  7221. return -1;
  7222. }
  7223. if( lctx->type.dataType.IsPrimitive() )
  7224. {
  7225. if( !lctx->type.isLValue )
  7226. {
  7227. Error(TXT_NOT_LVALUE, lexpr);
  7228. return -1;
  7229. }
  7230. if( op != ttAssignment )
  7231. {
  7232. // Compute the operator before the assignment
  7233. asCExprValue lvalue = lctx->type;
  7234. if( lctx->type.isTemporary && !lctx->type.isVariable )
  7235. {
  7236. // The temporary variable must not be freed until the
  7237. // assignment has been performed. lvalue still holds
  7238. // the information about the temporary variable
  7239. lctx->type.isTemporary = false;
  7240. }
  7241. asCExprContext o(engine);
  7242. CompileOperator(opNode, lctx, rctx, &o);
  7243. MergeExprBytecode(rctx, &o);
  7244. rctx->type = o.type;
  7245. // Convert the rvalue to the right type and validate it
  7246. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  7247. MergeExprBytecode(ctx, rctx);
  7248. lctx->type = lvalue;
  7249. // The lvalue continues the same, either it was a variable, or a reference in the register
  7250. }
  7251. else
  7252. {
  7253. // Convert the rvalue to the right type and validate it
  7254. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  7255. MergeExprBytecode(ctx, rctx);
  7256. MergeExprBytecode(ctx, lctx);
  7257. }
  7258. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7259. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7260. ctx->type = lctx->type;
  7261. }
  7262. else if( lctx->type.isExplicitHandle )
  7263. {
  7264. if( !lctx->type.isLValue )
  7265. {
  7266. Error(TXT_NOT_LVALUE, lexpr);
  7267. return -1;
  7268. }
  7269. // Object handles don't have any compound assignment operators
  7270. if( op != ttAssignment )
  7271. {
  7272. asCString str;
  7273. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7274. Error(str, lexpr);
  7275. return -1;
  7276. }
  7277. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  7278. {
  7279. // The object is a value type but that should be treated as a handle
  7280. // Make sure the right hand value is a handle
  7281. if( !rctx->type.isExplicitHandle &&
  7282. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  7283. {
  7284. // Function names can be considered handles already
  7285. if( rctx->methodName == "" )
  7286. {
  7287. asCDataType dt = rctx->type.dataType;
  7288. dt.MakeHandle(true);
  7289. dt.MakeReference(false);
  7290. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  7291. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7292. {
  7293. asCString str;
  7294. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7295. Error(str, rexpr);
  7296. return -1;
  7297. }
  7298. }
  7299. if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles())
  7300. {
  7301. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr);
  7302. return -1;
  7303. }
  7304. // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
  7305. // the code for moving the argument to the stack may not know to correctly handle the argument type
  7306. // in case of variable parameter type.
  7307. rctx->type.isExplicitHandle = true;
  7308. }
  7309. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  7310. {
  7311. // An overloaded assignment operator was found (or a compilation error occured)
  7312. return 0;
  7313. }
  7314. // The object must implement the opAssign method
  7315. asCString msg;
  7316. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7317. Error(msg.AddressOf(), opNode);
  7318. return -1;
  7319. }
  7320. else
  7321. {
  7322. asCDataType dt = lctx->type.dataType;
  7323. dt.MakeReference(false);
  7324. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF, true);
  7325. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7326. {
  7327. asCString str;
  7328. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7329. Error(str, rexpr);
  7330. return -1;
  7331. }
  7332. MergeExprBytecode(ctx, rctx);
  7333. MergeExprBytecode(ctx, lctx);
  7334. if(!rctx->type.isRefSafe)
  7335. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7336. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7337. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7338. ctx->type = lctx->type;
  7339. // After the handle assignment the original handle is left on the stack
  7340. ctx->type.dataType.MakeReference(false);
  7341. }
  7342. }
  7343. else // if( lctx->type.dataType.IsObject() )
  7344. {
  7345. // The lvalue reference may be marked as a temporary, if for example
  7346. // it was originated as a handle returned from a function. In such
  7347. // cases it must be possible to assign values to it anyway.
  7348. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7349. {
  7350. // Convert the handle to a object reference
  7351. asCDataType to;
  7352. to = lctx->type.dataType;
  7353. to.MakeHandle(false);
  7354. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  7355. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  7356. }
  7357. // Check for overloaded assignment operator
  7358. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  7359. {
  7360. // An overloaded assignment operator was found (or a compilation error occured)
  7361. return 0;
  7362. }
  7363. // No registered operator was found. In case the operation is a direct
  7364. // assignment and the rvalue is the same type as the lvalue, then we can
  7365. // still use the byte-for-byte copy to do the assignment
  7366. if( op != ttAssignment )
  7367. {
  7368. asCString str;
  7369. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7370. Error(str, lexpr);
  7371. return -1;
  7372. }
  7373. // If the left hand expression is simple, i.e. without any
  7374. // function calls or allocations of memory, then we can avoid
  7375. // doing a copy of the right hand expression (done by PrepareArgument).
  7376. // Instead the reference to the value can be placed directly on the
  7377. // stack.
  7378. //
  7379. // This optimization should only be done for value types, where
  7380. // the application developer is responsible for making the
  7381. // implementation safe against unwanted destruction of the input
  7382. // reference before the time.
  7383. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  7384. // Implicitly convert the rvalue to the type of the lvalue
  7385. bool needConversion = false;
  7386. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7387. needConversion = true;
  7388. if( !simpleExpr || needConversion )
  7389. {
  7390. if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle &&
  7391. !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  7392. {
  7393. // Make the conversion from handle to non-handle without creating
  7394. // a copy of the object (otherwise done by PrepareArgument)
  7395. asCDataType dt = rctx->type.dataType;
  7396. dt.MakeHandle(false);
  7397. ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV);
  7398. needConversion = false;
  7399. }
  7400. asCDataType dt = lctx->type.dataType;
  7401. dt.MakeReference(true);
  7402. // A funcdef can be accessed by ref, but only as read-only
  7403. if( dt.IsFuncdef() && !dt.IsObjectHandle() )
  7404. dt.MakeReadOnly(true);
  7405. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  7406. if( r < 0 )
  7407. return -1;
  7408. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7409. {
  7410. asCString str;
  7411. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7412. Error(str, rexpr);
  7413. return -1;
  7414. }
  7415. }
  7416. else
  7417. {
  7418. // Process any property accessor first, before placing the final reference on the stack
  7419. if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 )
  7420. return -1;
  7421. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  7422. rctx->bc.Instr(asBC_RDSPtr);
  7423. }
  7424. MergeExprBytecode(ctx, rctx);
  7425. MergeExprBytecode(ctx, lctx);
  7426. if( !simpleExpr || needConversion )
  7427. {
  7428. if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) )
  7429. {
  7430. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  7431. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  7432. // as the value allocated on the stack is guaranteed to be safe.
  7433. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  7434. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  7435. else
  7436. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7437. }
  7438. }
  7439. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7440. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7441. ctx->type = lctx->type;
  7442. }
  7443. return 0;
  7444. }
  7445. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  7446. {
  7447. asASSERT(expr->nodeType == snAssignment);
  7448. asCScriptNode *lexpr = expr->firstChild;
  7449. if( lexpr->next )
  7450. {
  7451. // Compile the two expression terms
  7452. asCExprContext lctx(engine), rctx(engine);
  7453. int rr = CompileAssignment(lexpr->next->next, &rctx);
  7454. int lr = CompileCondition(lexpr, &lctx);
  7455. if( lr >= 0 && rr >= 0 )
  7456. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  7457. // Since the operands failed, the assignment was not computed
  7458. ctx->type.SetDummy();
  7459. return -1;
  7460. }
  7461. return CompileCondition(lexpr, ctx);
  7462. }
  7463. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  7464. {
  7465. asCExprValue ctype;
  7466. // Compile the conditional expression
  7467. asCScriptNode *cexpr = expr->firstChild;
  7468. if( cexpr->next )
  7469. {
  7470. //-------------------------------
  7471. // Compile the condition
  7472. asCExprContext e(engine);
  7473. int r = CompileExpression(cexpr, &e);
  7474. if( r < 0 )
  7475. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7476. // Allow value types to be converted to bool using 'bool opImplConv()'
  7477. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  7478. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  7479. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7480. {
  7481. asCString str;
  7482. str.Format(TXT_EXPR_MUST_BE_BOOL_s, e.type.dataType.Format(outFunc->nameSpace).AddressOf());
  7483. Error(str, cexpr);
  7484. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7485. }
  7486. ctype = e.type;
  7487. if( ProcessPropertyGetAccessor(&e, cexpr) < 0)
  7488. return -1;
  7489. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  7490. ProcessDeferredParams(&e);
  7491. //-------------------------------
  7492. // Compile the left expression
  7493. asCExprContext le(engine);
  7494. int lr = CompileAssignment(cexpr->next, &le);
  7495. // Resolve any function names already
  7496. DetermineSingleFunc(&le, cexpr->next);
  7497. //-------------------------------
  7498. // Compile the right expression
  7499. asCExprContext re(engine);
  7500. int rr = CompileAssignment(cexpr->next->next, &re);
  7501. DetermineSingleFunc(&re, cexpr->next->next);
  7502. if (lr >= 0 && rr >= 0)
  7503. {
  7504. // Don't allow any operators on expressions that take address of class method
  7505. if (le.IsClassMethod() || re.IsClassMethod())
  7506. {
  7507. Error(TXT_INVALID_OP_ON_METHOD, expr);
  7508. return -1;
  7509. }
  7510. if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0)
  7511. return -1;
  7512. if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0)
  7513. return -1;
  7514. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  7515. // Allow an anonymous initialization list to be converted to the type in the other condition
  7516. if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
  7517. {
  7518. asCDataType to = re.type.dataType;
  7519. to.MakeReference(false);
  7520. to.MakeReadOnly(false);
  7521. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7522. }
  7523. else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory)
  7524. {
  7525. asCDataType to = le.type.dataType;
  7526. to.MakeReference(false);
  7527. to.MakeReadOnly(false);
  7528. ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7529. }
  7530. if (le.IsAnonymousInitList())
  7531. {
  7532. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
  7533. return -1;
  7534. }
  7535. else if (re.IsAnonymousInitList())
  7536. {
  7537. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next);
  7538. return -1;
  7539. }
  7540. // Try to perform an implicit cast to make the two operands of the same type
  7541. // Choose the conversion that is the least costly
  7542. if (le.type.dataType != re.type.dataType)
  7543. {
  7544. asCExprContext tmp(engine);
  7545. tmp.type = le.type;
  7546. tmp.type.dataType.MakeReference(false);
  7547. asUINT costAtoB = ImplicitConversion(&tmp, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, false);
  7548. if (!tmp.type.dataType.IsEqualExceptRef(re.type.dataType))
  7549. costAtoB = 0xFFFFFFFF;
  7550. tmp.type = re.type;
  7551. tmp.type.dataType.MakeReference(false);
  7552. asUINT costBtoA = ImplicitConversion(&tmp, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, false);
  7553. if (!tmp.type.dataType.IsEqualExceptRef(le.type.dataType))
  7554. costBtoA = 0xFFFFFFFF;
  7555. if (costAtoB < costBtoA && costAtoB != 0xFFFFFFFF)
  7556. {
  7557. if (le.type.dataType.IsObject())
  7558. Dereference(&le, true);
  7559. else
  7560. ConvertToVariable(&le);
  7561. ImplicitConversion(&le, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, true);
  7562. }
  7563. else if (costAtoB > costBtoA && costBtoA != 0xFFFFFFFF)
  7564. {
  7565. if( re.type.dataType.IsObject() )
  7566. Dereference(&re, true);
  7567. else
  7568. ConvertToVariable(&re);
  7569. ImplicitConversion(&re, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, true);
  7570. }
  7571. // If the cost for conversion is the same in both directions we have an ambigious situation,
  7572. // which we do not resolve. In that case the script need to perform an explicit conversion
  7573. }
  7574. // Allow a 0 to be implicitly converted to the other type
  7575. if (le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType())
  7576. {
  7577. asCDataType to = re.type.dataType;
  7578. to.MakeReference(false);
  7579. to.MakeReadOnly(true);
  7580. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7581. }
  7582. else if( re.type.isConstant && re.type.GetConstantData() == 0 && re.type.dataType.IsIntegerType())
  7583. {
  7584. asCDataType to = le.type.dataType;
  7585. to.MakeReference(false);
  7586. to.MakeReadOnly(true);
  7587. ImplicitConversionConstant(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7588. }
  7589. // Allow expression to be converted to handle if the other is handle
  7590. if (!le.type.dataType.IsObjectHandle() && re.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo() )
  7591. {
  7592. asCDataType dt = le.type.dataType;
  7593. dt.MakeHandle(true);
  7594. ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV);
  7595. }
  7596. if (!re.type.dataType.IsObjectHandle() && le.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo())
  7597. {
  7598. asCDataType dt = re.type.dataType;
  7599. dt.MakeHandle(true);
  7600. ImplicitConversion(&re, dt, cexpr->next->next, asIC_IMPLICIT_CONV);
  7601. }
  7602. // If the type of the expressions can be handle, then make them so for efficiency
  7603. if (le.type.dataType.SupportHandles() && re.type.dataType.SupportHandles())
  7604. {
  7605. asCDataType dt = le.type.dataType;
  7606. dt.MakeHandle(true);
  7607. ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV);
  7608. dt = re.type.dataType;
  7609. dt.MakeHandle(true);
  7610. ImplicitConversion(&re, dt, cexpr->next->next, asIC_IMPLICIT_CONV);
  7611. }
  7612. // Allow either case to be converted to const @ if the other is const @
  7613. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  7614. {
  7615. le.type.dataType.MakeHandleToConst(true);
  7616. re.type.dataType.MakeHandleToConst(true);
  7617. }
  7618. // Make sure both expressions have the same type
  7619. if (!le.type.dataType.IsEqualExceptRefAndConst(re.type.dataType))
  7620. {
  7621. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7622. return -1;
  7623. }
  7624. //---------------------------------
  7625. // Output the byte code
  7626. int afterLabel = nextLabel++;
  7627. int elseLabel = nextLabel++;
  7628. // If left expression is void, then we don't need to store the result
  7629. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  7630. {
  7631. // Put the code for the condition expression on the output
  7632. MergeExprBytecode(ctx, &e);
  7633. // Added the branch decision
  7634. ctx->type = e.type;
  7635. ConvertToVariable(ctx);
  7636. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)ctx->type.stackOffset);
  7637. ctx->bc.Instr(asBC_ClrHi);
  7638. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7639. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7640. // Add the left expression
  7641. MergeExprBytecode(ctx, &le);
  7642. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7643. // Add the right expression
  7644. ctx->bc.Label((short)elseLabel);
  7645. MergeExprBytecode(ctx, &re);
  7646. ctx->bc.Label((short)afterLabel);
  7647. // Set the type of the result
  7648. ctx->type = le.type;
  7649. }
  7650. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7651. {
  7652. // Special case for when both results are 'null'
  7653. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7654. // Put the code for the condition expression on the output
  7655. MergeExprBytecode(ctx, &e);
  7656. // Load the result into the register, but ignore the value since both paths give the same response
  7657. ctx->type = e.type;
  7658. ConvertToVariable(ctx);
  7659. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)ctx->type.stackOffset);
  7660. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7661. // Return a null constant
  7662. ctx->bc.Instr(asBC_PshNull);
  7663. ctx->type.SetNullConstant();
  7664. }
  7665. else
  7666. {
  7667. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7668. //
  7669. // Restrictions for the condition to be used as lvalue:
  7670. // 1. both b and c must be of the same type and be lvalue references
  7671. // 2. neither of the expressions can have any deferred arguments
  7672. // that would have to be cleaned up after the reference
  7673. // 3. neither expression can be temporary
  7674. //
  7675. // If either expression is local, the resulting lvalue is not valid
  7676. // for return since it is not allowed to return references to local
  7677. // variables.
  7678. //
  7679. // The reference to the local variable must be loaded into the register,
  7680. // the resulting expression must not be considered as a local variable
  7681. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7682. if( le.type.isLValue && re.type.isLValue &&
  7683. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() == 0 &&
  7684. !le.type.isTemporary && !re.type.isTemporary &&
  7685. le.type.dataType == re.type.dataType )
  7686. {
  7687. // Put the code for the condition expression on the output
  7688. MergeExprBytecode(ctx, &e);
  7689. // Add the branch decision
  7690. ctx->type = e.type;
  7691. ConvertToVariable(ctx);
  7692. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)ctx->type.stackOffset);
  7693. ctx->bc.Instr(asBC_ClrHi);
  7694. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7695. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7696. // Start of the left expression
  7697. MergeExprBytecode(ctx, &le);
  7698. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7699. {
  7700. // Load the address of the variable into the register
  7701. ctx->bc.InstrSHORT(asBC_LDV, (short)le.type.stackOffset);
  7702. }
  7703. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7704. // Start of the right expression
  7705. ctx->bc.Label((short)elseLabel);
  7706. MergeExprBytecode(ctx, &re);
  7707. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7708. {
  7709. // Load the address of the variable into the register
  7710. ctx->bc.InstrSHORT(asBC_LDV, (short)re.type.stackOffset);
  7711. }
  7712. ctx->bc.Label((short)afterLabel);
  7713. // In case the options were to objects, it is necessary to dereference the pointer on
  7714. // the stack so it will point to the actual object, instead of the variable
  7715. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7716. {
  7717. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7718. ctx->bc.Instr(asBC_RDSPtr);
  7719. }
  7720. // The result is an lvalue
  7721. ctx->type.isLValue = true;
  7722. ctx->type.dataType = le.type.dataType;
  7723. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7724. ctx->type.dataType.MakeReference(true);
  7725. else
  7726. ctx->type.dataType.MakeReference(false);
  7727. // It can't be a treated as a variable, since we don't know which one was used
  7728. ctx->type.isVariable = false;
  7729. ctx->type.isTemporary = false;
  7730. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7731. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7732. }
  7733. else
  7734. {
  7735. // Allocate temporary variable and copy the result to that one
  7736. asCExprValue temp;
  7737. temp = le.type;
  7738. temp.dataType.MakeReference(false);
  7739. temp.dataType.MakeReadOnly(false);
  7740. // Make sure the variable isn't used in any of the expressions,
  7741. // as it would be overwritten which may cause crashes or less visible bugs
  7742. int l = int(reservedVariables.GetLength());
  7743. e.bc.GetVarsUsed(reservedVariables);
  7744. le.bc.GetVarsUsed(reservedVariables);
  7745. re.bc.GetVarsUsed(reservedVariables);
  7746. int offset = AllocateVariable(temp.dataType, true, false);
  7747. reservedVariables.SetLength(l);
  7748. temp.SetVariable(temp.dataType, offset, true);
  7749. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7750. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7751. // Put the code for the condition expression on the output
  7752. MergeExprBytecode(ctx, &e);
  7753. // Add the branch decision
  7754. ctx->type = e.type;
  7755. ConvertToVariable(ctx);
  7756. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)ctx->type.stackOffset);
  7757. ctx->bc.Instr(asBC_ClrHi);
  7758. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7759. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7760. // Assign the result of the left expression to the temporary variable
  7761. asCExprValue rtemp;
  7762. rtemp = temp;
  7763. if( rtemp.dataType.IsObjectHandle() )
  7764. rtemp.isExplicitHandle = true;
  7765. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7766. MergeExprBytecode(ctx, &le);
  7767. if( !rtemp.dataType.IsPrimitive() )
  7768. {
  7769. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7770. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7771. }
  7772. asCExprValue result;
  7773. result = rtemp;
  7774. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7775. if( !result.dataType.IsPrimitive() )
  7776. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7777. // Release the old temporary variable
  7778. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7779. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7780. ProcessDeferredParams(ctx);
  7781. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7782. // Start of the right expression
  7783. ctx->bc.Label((short)elseLabel);
  7784. // Copy the result to the same temporary variable
  7785. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7786. MergeExprBytecode(ctx, &re);
  7787. if( !rtemp.dataType.IsPrimitive() )
  7788. {
  7789. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7790. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7791. }
  7792. result = rtemp;
  7793. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7794. if( !result.dataType.IsPrimitive() )
  7795. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7796. // Release the old temporary variable
  7797. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7798. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7799. ProcessDeferredParams(ctx);
  7800. ctx->bc.Label((short)afterLabel);
  7801. // Set the temporary variable as output
  7802. ctx->type = rtemp;
  7803. ctx->type.isExplicitHandle = isExplicitHandle;
  7804. if( !ctx->type.dataType.IsPrimitive() )
  7805. {
  7806. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7807. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7808. }
  7809. // Make sure the output isn't marked as being a literal constant
  7810. ctx->type.isConstant = false;
  7811. }
  7812. }
  7813. }
  7814. else
  7815. {
  7816. ctx->type.SetDummy();
  7817. return -1;
  7818. }
  7819. }
  7820. else
  7821. return CompileExpression(cexpr, ctx);
  7822. return 0;
  7823. }
  7824. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7825. {
  7826. asASSERT(expr->nodeType == snExpression);
  7827. // Convert to polish post fix, i.e: a+b => ab+
  7828. asCArray<asCScriptNode *> postfix;
  7829. ConvertToPostFix(expr, postfix);
  7830. // Compile the postfix formatted expression
  7831. return CompilePostFixExpression(&postfix, ctx);
  7832. }
  7833. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7834. {
  7835. // The algorithm that I've implemented here is similar to
  7836. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7837. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7838. // Count the nodes in order to preallocate the buffers
  7839. int count = 0;
  7840. asCScriptNode *node = expr->firstChild;
  7841. while( node )
  7842. {
  7843. count++;
  7844. node = node->next;
  7845. }
  7846. asCArray<asCScriptNode *> stackA(count);
  7847. asCArray<asCScriptNode *> &stackB = postfix;
  7848. stackB.Allocate(count, false);
  7849. node = expr->firstChild;
  7850. while( node )
  7851. {
  7852. int precedence = GetPrecedence(node);
  7853. while( stackA.GetLength() > 0 &&
  7854. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7855. stackB.PushLast(stackA.PopLast());
  7856. stackA.PushLast(node);
  7857. node = node->next;
  7858. }
  7859. while( stackA.GetLength() > 0 )
  7860. stackB.PushLast(stackA.PopLast());
  7861. }
  7862. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7863. {
  7864. // Shouldn't send any byte code
  7865. asASSERT(ctx->bc.GetLastInstr() == -1);
  7866. // Set the context to a dummy type to avoid further
  7867. // errors in case the expression fails to compile
  7868. ctx->type.SetDummy();
  7869. // Evaluate the operands and operators
  7870. asCArray<asCExprContext*> free;
  7871. asCArray<asCExprContext*> expr;
  7872. int ret = 0;
  7873. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7874. {
  7875. asCScriptNode *node = (*postfix)[n];
  7876. if( node->nodeType == snExprTerm )
  7877. {
  7878. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7879. expr.PushLast(e);
  7880. e->exprNode = node;
  7881. ret = CompileExpressionTerm(node, e);
  7882. }
  7883. else
  7884. {
  7885. asCExprContext *r = expr.PopLast();
  7886. asCExprContext *l = expr.PopLast();
  7887. // Now compile the operator
  7888. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7889. ret = CompileOperator(node, l, r, e);
  7890. expr.PushLast(e);
  7891. // Free the operands
  7892. l->Clear();
  7893. free.PushLast(l);
  7894. r->Clear();
  7895. free.PushLast(r);
  7896. }
  7897. }
  7898. if( ret == 0 )
  7899. {
  7900. asASSERT(expr.GetLength() == 1);
  7901. // The final result should be moved to the output context
  7902. MergeExprBytecodeAndType(ctx, expr[0]);
  7903. }
  7904. // Clean up
  7905. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7906. asDELETE(expr[e], asCExprContext);
  7907. for( asUINT f = 0; f < free.GetLength(); f++ )
  7908. asDELETE(free[f], asCExprContext);
  7909. return ret;
  7910. }
  7911. int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7912. {
  7913. asASSERT(node->nodeType == snInitList);
  7914. // Do not allow constructing non-shared types in shared functions
  7915. if (outFunc->IsShared() &&
  7916. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7917. {
  7918. asCString msg;
  7919. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7920. Error(msg, node);
  7921. }
  7922. // If this is compiled from a default arg, then use the script code for the default arg
  7923. asCScriptCode *origCode = script;
  7924. if (ctx->origCode)
  7925. script = ctx->origCode;
  7926. // Allocate and initialize the temporary object
  7927. int offset = AllocateVariable(dt, true);
  7928. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7929. // Push the reference to the object on the stack
  7930. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7931. ctx->type.SetVariable(dt, offset, true);
  7932. ctx->type.isLValue = false;
  7933. // If the variable is allocated on the heap we have a reference,
  7934. // otherwise the actual object pointer is pushed on the stack.
  7935. if (IsVariableOnHeap(offset))
  7936. ctx->type.dataType.MakeReference(true);
  7937. // Clear the flag for anonymous initalization list as it is no
  7938. // longer true now that the object has been initialized.
  7939. ctx->isAnonymousInitList = false;
  7940. ctx->origCode = 0;
  7941. script = origCode;
  7942. return 0;
  7943. }
  7944. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7945. {
  7946. // Shouldn't send any byte code
  7947. asASSERT(ctx->bc.GetLastInstr() == -1);
  7948. // Check if this is an initialization of a temp object with an initialization list
  7949. if (node->firstChild )
  7950. {
  7951. if (node->firstChild->nodeType == snDataType)
  7952. {
  7953. // Determine the type of the temporary object
  7954. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7955. return CompileAnonymousInitList(node->lastChild, ctx, dt);
  7956. }
  7957. else if (node->firstChild->nodeType == snInitList)
  7958. {
  7959. // As the type is not yet known, the init list will be compiled at a
  7960. // later time when the type can be determined from the destination
  7961. ctx->SetAnonymousInitList(node->firstChild, script);
  7962. return 0;
  7963. }
  7964. }
  7965. // Set the type as a dummy by default, in case of any compiler errors
  7966. ctx->type.SetDummy();
  7967. // Compile the value node
  7968. asCScriptNode *vnode = node->firstChild;
  7969. while( vnode->nodeType != snExprValue )
  7970. vnode = vnode->next;
  7971. asCExprContext v(engine);
  7972. int r = CompileExpressionValue(vnode, &v);
  7973. if( r < 0 )
  7974. return r;
  7975. // Compile post fix operators
  7976. asCScriptNode *pnode = vnode->next;
  7977. while( pnode )
  7978. {
  7979. r = CompileExpressionPostOp(pnode, &v);
  7980. if( r < 0 )
  7981. return r;
  7982. pnode = pnode->next;
  7983. }
  7984. // Compile pre fix operators
  7985. pnode = vnode->prev;
  7986. while( pnode )
  7987. {
  7988. r = CompileExpressionPreOp(pnode, &v);
  7989. if( r < 0 )
  7990. return r;
  7991. pnode = pnode->prev;
  7992. }
  7993. // Return the byte code and final type description
  7994. MergeExprBytecodeAndType(ctx, &v);
  7995. return 0;
  7996. }
  7997. // returns:
  7998. // SL_LOCALCONST = local constant
  7999. // SL_LOCALVAR = local variable
  8000. // SL_NOMATCH = no match
  8001. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult)
  8002. {
  8003. sVariable *v = 0;
  8004. if (variables)
  8005. v = variables->GetVariable(name.AddressOf());
  8006. if (v)
  8007. {
  8008. if (v->isPureConstant)
  8009. {
  8010. outResult->type.SetConstantData(v->type, v->constantValue);
  8011. return SL_LOCALCONST;
  8012. }
  8013. outResult->type.SetVariable(v->type, v->stackOffset, false);
  8014. return SL_LOCALVAR;
  8015. }
  8016. return SL_NOMATCH;
  8017. }
  8018. // returns:
  8019. // SL_CLASSPROPACCESS = class property accessor
  8020. // SL_CLASSPROP = class property
  8021. // SL_CLASSMETHOD = class method
  8022. // SL_CLASSTYPE = class child type
  8023. // SL_NOMATCH = no match
  8024. // SL_ERROR = error
  8025. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult)
  8026. {
  8027. // See if there are any matching property accessors
  8028. asCExprContext access(engine);
  8029. access.type.Set(asCDataType::CreateType(objType, false));
  8030. access.type.dataType.MakeReference(true);
  8031. int r = 0;
  8032. // Indexed property access
  8033. asCExprContext dummyArg(engine);
  8034. r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true);
  8035. if (r == 0)
  8036. {
  8037. // Normal property access
  8038. r = FindPropertyAccessor(name, &access, 0, 0, true);
  8039. }
  8040. if (r <= -3) return SL_ERROR;
  8041. if (r != 0)
  8042. {
  8043. // The symbol matches getters/setters (though not necessarily a compilable match)
  8044. MergeExprBytecodeAndType(outResult, &access);
  8045. outResult->type.dataType.SetTypeInfo(objType);
  8046. return SL_CLASSPROPACCESS;
  8047. }
  8048. // Look for matching properties
  8049. asCDataType dt;
  8050. dt = asCDataType::CreateType(objType, false);
  8051. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8052. if (prop)
  8053. {
  8054. outResult->type.dataType.SetTypeInfo(objType);
  8055. return SL_CLASSPROP;
  8056. }
  8057. // If it is not a property, it may still be the name of a method
  8058. asCObjectType *ot = objType;
  8059. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8060. {
  8061. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8062. if (f->name == name &&
  8063. (builder->module->m_accessMask & f->accessMask))
  8064. {
  8065. outResult->type.dataType.SetTypeInfo(objType);
  8066. return SL_CLASSMETHOD;
  8067. }
  8068. }
  8069. // If it is not a method, then it can still be a child type
  8070. for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
  8071. {
  8072. if (ot->childFuncDefs[n]->name == name)
  8073. {
  8074. outResult->type.dataType.SetTypeInfo(objType);
  8075. return SL_CLASSTYPE;
  8076. }
  8077. }
  8078. return SL_NOMATCH;
  8079. }
  8080. // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy
  8081. // The 'outResult' will be used to return info on what was identified, but no code will be produced by this function
  8082. // input:
  8083. // name = the name of the symbol to look for
  8084. // scope = explicit scope informed
  8085. // 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
  8086. // returns:
  8087. // SL_NOMATCH = no matching symbol
  8088. // SL_LOCALCONST = local constant
  8089. // SL_LOCALVAR = local variable
  8090. // SL_THISPTR = this pointer
  8091. // SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found
  8092. // SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found
  8093. // SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found
  8094. // SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found
  8095. // SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8096. // SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8097. // SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8098. // SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8099. // SL_GLOBALTYPE = type, lookupResult->dataType holds the type
  8100. // SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8101. // SL_ERROR = error
  8102. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult)
  8103. {
  8104. asASSERT(outResult);
  8105. // It is a local variable or parameter?
  8106. // This is not accessible by default arg expressions
  8107. if (!isCompilingDefaultArg && scope == "" && !objType )
  8108. {
  8109. SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult);
  8110. if (r != 0)
  8111. return r;
  8112. }
  8113. // Is it a class member?
  8114. if (scope == "" && ((objType) || (outFunc && outFunc->objectType)))
  8115. {
  8116. // 'this' is not accessible by default arg expressions
  8117. if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg)
  8118. {
  8119. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8120. // The object pointer is located at stack position 0
  8121. outResult->type.SetVariable(dt, 0, false);
  8122. return SL_THISPTR;
  8123. }
  8124. // 'super' is not accessible by default arg expressions
  8125. if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg)
  8126. {
  8127. // If the class is derived from another class, then super can be used to call the base' class constructor
  8128. if (outFunc && outFunc->objectType->derivedFrom)
  8129. {
  8130. outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom);
  8131. return SL_CLASSMETHOD;
  8132. }
  8133. }
  8134. // Look for members in the type
  8135. // class members are only accessible in default arg expressions as post op '.'
  8136. if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) )
  8137. {
  8138. SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult);
  8139. if (r != 0)
  8140. return r;
  8141. }
  8142. }
  8143. // Recursively search parent namespaces for global entities
  8144. asSNameSpace *currNamespace = DetermineNameSpace("");
  8145. while( !objType && currNamespace )
  8146. {
  8147. asCString currScope = scope;
  8148. // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
  8149. // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
  8150. int n = currScope.FindLast("::");
  8151. asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
  8152. asCString nsName = n >= 0 ? currScope.SubString(0, n) : asCString("");
  8153. // If the scope represents a type that the current class inherits
  8154. // from then that should be used instead of going through the namespaces
  8155. if (nsName == "" && (outFunc && outFunc->objectType))
  8156. {
  8157. asCObjectType *ot = outFunc->objectType;
  8158. while (ot)
  8159. {
  8160. if (ot->name == typeName)
  8161. {
  8162. SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult);
  8163. if (r != 0)
  8164. return r;
  8165. }
  8166. ot = ot->derivedFrom;
  8167. }
  8168. }
  8169. // If the scope starts with :: then search from the global scope
  8170. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8171. {
  8172. if (nsName != "")
  8173. {
  8174. if (currNamespace->name != "")
  8175. nsName = currNamespace->name + "::" + nsName;
  8176. }
  8177. else
  8178. nsName = currNamespace->name;
  8179. }
  8180. else
  8181. nsName = nsName.SubString(2);
  8182. // Get the namespace for this scope
  8183. asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf());
  8184. if (ns)
  8185. {
  8186. // Is there a type with typeName in the namespace?
  8187. asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0);
  8188. // Check if the symbol is a member of that type
  8189. if (scopeType)
  8190. {
  8191. // Is it an object type?
  8192. if (CastToObjectType(scopeType))
  8193. {
  8194. SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult);
  8195. if (r != 0)
  8196. return r;
  8197. }
  8198. // Is it an enum type?
  8199. if (CastToEnumType(scopeType))
  8200. {
  8201. asDWORD value = 0;
  8202. asCDataType dt;
  8203. if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value))
  8204. {
  8205. // an enum value was resolved
  8206. outResult->type.SetConstantDW(dt, value);
  8207. outResult->symbolNamespace = ns;
  8208. return SL_ENUMVAL;
  8209. }
  8210. }
  8211. }
  8212. }
  8213. // Get the namespace for this scope. This may return null if the scope is an enum
  8214. nsName = currScope;
  8215. // If the scope starts with :: then search from the global scope
  8216. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8217. {
  8218. if (nsName != "")
  8219. {
  8220. if (currNamespace->name != "")
  8221. nsName = currNamespace->name + "::" + nsName;
  8222. }
  8223. else
  8224. nsName = currNamespace->name;
  8225. }
  8226. else
  8227. nsName = nsName.SubString(2);
  8228. ns = engine->FindNameSpace(nsName.AddressOf());
  8229. // Is it a global property?
  8230. if (ns)
  8231. {
  8232. // See if there are any matching global property accessors
  8233. asCExprContext access(engine);
  8234. int r = 0;
  8235. // Indexed property access
  8236. asCExprContext dummyArg(engine);
  8237. r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns);
  8238. if (r == 0)
  8239. {
  8240. // Normal property access
  8241. r = FindPropertyAccessor(name, &access, 0, ns);
  8242. }
  8243. if (r <= -3) return SL_ERROR;
  8244. if (r != 0)
  8245. {
  8246. // The symbol matches getters/setters (though not necessarily a compilable match)
  8247. MergeExprBytecodeAndType(outResult, &access);
  8248. outResult->symbolNamespace = ns;
  8249. return SL_GLOBALPROPACCESS;
  8250. }
  8251. // See if there is any matching global property
  8252. bool isCompiled = true;
  8253. bool isPureConstant = false;
  8254. bool isAppProp = false;
  8255. asQWORD constantValue = 0;
  8256. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8257. if (prop)
  8258. {
  8259. // If the global property is a pure constant
  8260. // we can allow the compiler to optimize it. Pure
  8261. // constants are global constant variables that were
  8262. // initialized by literal constants.
  8263. if (isPureConstant)
  8264. {
  8265. outResult->type.SetConstantData(prop->type, constantValue);
  8266. outResult->symbolNamespace = ns;
  8267. return SL_GLOBALCONST;
  8268. }
  8269. else
  8270. {
  8271. outResult->type.Set(prop->type);
  8272. outResult->symbolNamespace = ns;
  8273. return SL_GLOBALVAR;
  8274. }
  8275. }
  8276. }
  8277. // Is it the name of a global function?
  8278. if (ns)
  8279. {
  8280. asCArray<int> funcs;
  8281. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8282. if (funcs.GetLength() > 0)
  8283. {
  8284. // Defer the evaluation of which function until it is actually used
  8285. // Store the namespace and name of the function for later
  8286. outResult->type.SetUndefinedFuncHandle(engine);
  8287. outResult->methodName = ns ? ns->name + "::" + name : name;
  8288. outResult->symbolNamespace = ns;
  8289. return SL_GLOBALFUNC;
  8290. }
  8291. }
  8292. // Check for type names
  8293. if (ns)
  8294. {
  8295. asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0);
  8296. if (type)
  8297. {
  8298. outResult->type.dataType = asCDataType::CreateType(type, false);
  8299. return SL_GLOBALTYPE;
  8300. }
  8301. }
  8302. // Is it an enum value?
  8303. if (ns && !engine->ep.requireEnumScope)
  8304. {
  8305. // Look for the enum value without explicitly informing the enum type
  8306. asDWORD value = 0;
  8307. asCDataType dt;
  8308. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  8309. if (e)
  8310. {
  8311. if (e == 2)
  8312. {
  8313. // Ambiguous enum value: Save the name for resolution later.
  8314. // The ambiguity could be resolved now, but I hesitate
  8315. // to store too much information in the context.
  8316. outResult->enumValue = name.AddressOf();
  8317. // We cannot set a dummy value because it will pass through
  8318. // cleanly as an integer.
  8319. outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8320. outResult->symbolNamespace = ns;
  8321. return SL_ENUMVAL;
  8322. }
  8323. else
  8324. {
  8325. // an enum value was resolved
  8326. outResult->type.SetConstantDW(dt, value);
  8327. outResult->symbolNamespace = ns;
  8328. return SL_ENUMVAL;
  8329. }
  8330. }
  8331. }
  8332. // If the given scope starts with '::' then the search starts from global scope
  8333. if (scope.GetLength() >= 2 && scope[0] == ':')
  8334. break;
  8335. // Move up to parent namespace
  8336. currNamespace = engine->GetParentNameSpace(currNamespace);
  8337. }
  8338. // The name doesn't match any symbol
  8339. return SL_NOMATCH;
  8340. }
  8341. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType)
  8342. {
  8343. asCExprContext lookupResult(engine);
  8344. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult);
  8345. if (symbolType < 0)
  8346. {
  8347. // Give dummy value
  8348. ctx->type.SetDummy();
  8349. return -1;
  8350. }
  8351. if (symbolType == SL_NOMATCH)
  8352. {
  8353. // Give dummy value
  8354. ctx->type.SetDummy();
  8355. if (!isOptional)
  8356. {
  8357. // No matching symbol
  8358. asCString msg;
  8359. asCString smbl;
  8360. if (scope == "::")
  8361. smbl = scope;
  8362. else if (scope != "")
  8363. smbl = scope + "::";
  8364. smbl += name;
  8365. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  8366. Error(msg, errNode);
  8367. }
  8368. return -1;
  8369. }
  8370. // It is a local variable or parameter?
  8371. if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR )
  8372. {
  8373. // This is not accessible by default arg expressions
  8374. asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables);
  8375. sVariable *v = variables->GetVariable(name.AddressOf());
  8376. asASSERT(v);
  8377. if( v->isPureConstant )
  8378. ctx->type.SetConstantData(v->type, v->constantValue);
  8379. else if( v->type.IsPrimitive() )
  8380. {
  8381. if( v->type.IsReference() )
  8382. {
  8383. // Copy the reference into the register
  8384. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  8385. ctx->bc.Instr(asBC_PopRPtr);
  8386. ctx->type.Set(v->type);
  8387. }
  8388. else
  8389. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8390. // Set as lvalue unless it is a const variable
  8391. if( !v->type.IsReadOnly() )
  8392. ctx->type.isLValue = true;
  8393. }
  8394. else
  8395. {
  8396. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  8397. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8398. // If the variable is allocated on the heap we have a reference,
  8399. // otherwise the actual object pointer is pushed on the stack.
  8400. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  8401. // Implicitly dereference handle parameters sent by reference
  8402. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  8403. ctx->bc.Instr(asBC_RDSPtr);
  8404. // Mark the object as safe for access unless it is a handle, as the
  8405. // life time of the object is guaranteed throughout the scope.
  8406. if( !v->type.IsObjectHandle() )
  8407. ctx->type.isRefSafe = true;
  8408. // Set as lvalue unless it is a const variable
  8409. if (!v->type.IsReadOnly())
  8410. ctx->type.isLValue = true;
  8411. }
  8412. return 0;
  8413. }
  8414. // Is it a class member?
  8415. if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR)
  8416. {
  8417. // This is not accessible by default arg expressions
  8418. asASSERT(!isCompilingDefaultArg);
  8419. if (symbolType == SL_THISPTR)
  8420. {
  8421. asASSERT(name == THIS_TOKEN && !objType && scope == "");
  8422. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8423. // The object pointer is located at stack position 0
  8424. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8425. ctx->type.SetVariable(dt, 0, false);
  8426. ctx->type.dataType.MakeReference(true);
  8427. ctx->type.isLValue = true;
  8428. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  8429. ctx->type.isRefSafe = true;
  8430. return 0;
  8431. }
  8432. if (symbolType == SL_CLASSPROPACCESS)
  8433. {
  8434. if (scope != "")
  8435. {
  8436. // Cannot access non-static members like this
  8437. asCString msg;
  8438. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8439. Error(msg, errNode);
  8440. return -1;
  8441. }
  8442. // See if there are any matching property accessors
  8443. asCExprContext access(engine);
  8444. if (objType)
  8445. access.type.Set(asCDataType::CreateType(objType, false));
  8446. else
  8447. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
  8448. access.type.dataType.MakeReference(true);
  8449. int r = 0;
  8450. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8451. {
  8452. // This is an index access, check if there is a property accessor that takes an index arg
  8453. asCExprContext dummyArg(engine);
  8454. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  8455. }
  8456. if (r == 0)
  8457. {
  8458. // Normal property access
  8459. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  8460. }
  8461. if (r < 0) return -1;
  8462. if (access.property_get == 0 && access.property_set == 0)
  8463. {
  8464. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8465. asCString msg;
  8466. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8467. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8468. else
  8469. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8470. Error(msg, errNode);
  8471. return -1;
  8472. }
  8473. if (!objType)
  8474. {
  8475. // Prepare the bytecode for the member access
  8476. // This is only done when accessing through the implicit this pointer
  8477. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8478. }
  8479. MergeExprBytecodeAndType(ctx, &access);
  8480. return 0;
  8481. }
  8482. if (symbolType == SL_CLASSPROP)
  8483. {
  8484. if (scope != "")
  8485. {
  8486. // Cannot access non-static members like this
  8487. asCString msg;
  8488. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8489. Error(msg, errNode);
  8490. return -1;
  8491. }
  8492. asCDataType dt;
  8493. if (objType)
  8494. dt = asCDataType::CreateType(objType, false);
  8495. else
  8496. dt = asCDataType::CreateType(outFunc->objectType, false);
  8497. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8498. asASSERT(prop);
  8499. // Is the property access allowed?
  8500. if (prop->isPrivate && prop->isInherited)
  8501. {
  8502. if (engine->ep.privatePropAsProtected)
  8503. {
  8504. // The application is allowing inherited classes to access private properties of the parent
  8505. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  8506. // as it was how the compiler behaved earlier.
  8507. asCString msg;
  8508. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  8509. Warning(msg, errNode);
  8510. }
  8511. else
  8512. {
  8513. asCString msg;
  8514. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8515. Error(msg, errNode);
  8516. }
  8517. }
  8518. if (!objType)
  8519. {
  8520. // The object pointer is located at stack position 0
  8521. // This is only done when accessing through the implicit this pointer
  8522. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8523. ctx->type.SetVariable(dt, 0, false);
  8524. ctx->type.dataType.MakeReference(true);
  8525. Dereference(ctx, true);
  8526. }
  8527. // TODO: This is the same as what is in CompileExpressionPostOp
  8528. // Put the offset on the stack
  8529. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  8530. if (prop->type.IsReference())
  8531. ctx->bc.Instr(asBC_RDSPtr);
  8532. // Reference to primitive must be stored in the temp register
  8533. if (prop->type.IsPrimitive())
  8534. {
  8535. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  8536. ctx->bc.Instr(asBC_PopRPtr);
  8537. }
  8538. // Set the new type (keeping info about temp variable)
  8539. ctx->type.dataType = prop->type;
  8540. ctx->type.dataType.MakeReference(true);
  8541. ctx->type.isVariable = false;
  8542. ctx->type.isLValue = true;
  8543. if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())
  8544. {
  8545. // Objects that are members are not references
  8546. ctx->type.dataType.MakeReference(false);
  8547. // Objects that are members but not handles are safe as long as the parent object is safe
  8548. if (!objType || ctx->type.isRefSafe)
  8549. ctx->type.isRefSafe = true;
  8550. }
  8551. else if (ctx->type.dataType.IsObjectHandle())
  8552. {
  8553. // Objects accessed through handles cannot be considered safe
  8554. // as the handle can be cleared at any time
  8555. ctx->type.isRefSafe = false;
  8556. }
  8557. // If the object reference is const, the property will also be const
  8558. ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
  8559. return 0;
  8560. }
  8561. if (symbolType == SL_CLASSMETHOD)
  8562. {
  8563. if (scope != "")
  8564. {
  8565. // Cannot access non-static members like this
  8566. asCString msg;
  8567. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8568. Error(msg, errNode);
  8569. return -1;
  8570. }
  8571. #if AS_DEBUG
  8572. // If it is not a property, it may still be the name of a method which can be used to create delegates
  8573. asCObjectType *ot = outFunc->objectType;
  8574. asCScriptFunction *func = 0;
  8575. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8576. {
  8577. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8578. if (f->name == name &&
  8579. (builder->module->m_accessMask & f->accessMask))
  8580. {
  8581. func = f;
  8582. break;
  8583. }
  8584. }
  8585. asASSERT(func);
  8586. #endif
  8587. // An object method was found. Keep the name of the method in the expression, but
  8588. // don't actually modify the bytecode at this point since it is not yet known what
  8589. // the method will be used for, or even what overloaded method should be used.
  8590. ctx->methodName = name;
  8591. // Place the object pointer on the stack, as if the expression was this.func
  8592. if (!objType)
  8593. {
  8594. // The object pointer is located at stack position 0
  8595. // This is only done when accessing through the implicit this pointer
  8596. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8597. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  8598. ctx->type.dataType.MakeReference(true);
  8599. Dereference(ctx, true);
  8600. }
  8601. return 0;
  8602. }
  8603. }
  8604. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL)
  8605. {
  8606. // Get the namespace from SymbolLookup
  8607. asSNameSpace *ns = lookupResult.symbolNamespace;
  8608. if (symbolType == SL_GLOBALPROPACCESS)
  8609. {
  8610. // See if there are any matching global property accessors
  8611. asCExprContext access(engine);
  8612. int r = 0;
  8613. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8614. {
  8615. // This is an index access, check if there is a property accessor that takes an index arg
  8616. asCExprContext dummyArg(engine);
  8617. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  8618. }
  8619. if (r == 0)
  8620. {
  8621. // Normal property access
  8622. r = FindPropertyAccessor(name, &access, errNode, ns);
  8623. }
  8624. if (r < 0) return -1;
  8625. if (access.property_get == 0 && access.property_set == 0)
  8626. {
  8627. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8628. asCString msg;
  8629. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8630. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8631. else
  8632. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8633. Error(msg, errNode);
  8634. return -1;
  8635. }
  8636. // Prepare the bytecode for the function call
  8637. MergeExprBytecodeAndType(ctx, &access);
  8638. return 0;
  8639. }
  8640. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR)
  8641. {
  8642. bool isCompiled = true;
  8643. bool isPureConstant = false;
  8644. bool isAppProp = false;
  8645. asQWORD constantValue = 0;
  8646. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8647. asASSERT(prop);
  8648. // Verify that the global property has been compiled already
  8649. if (!isCompiled)
  8650. {
  8651. asCString str;
  8652. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  8653. Error(str, errNode);
  8654. return -1;
  8655. }
  8656. // If the global property is a pure constant
  8657. // we can allow the compiler to optimize it. Pure
  8658. // constants are global constant variables that were
  8659. // initialized by literal constants.
  8660. if (isPureConstant)
  8661. ctx->type.SetConstantData(prop->type, constantValue);
  8662. else
  8663. {
  8664. // A shared type must not access global vars, unless they
  8665. // too are shared, e.g. application registered vars
  8666. if (outFunc->IsShared())
  8667. {
  8668. if (!isAppProp)
  8669. {
  8670. asCString str;
  8671. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  8672. Error(str, errNode);
  8673. // Allow the compilation to continue to catch other problems
  8674. }
  8675. }
  8676. ctx->type.Set(prop->type);
  8677. ctx->type.isLValue = true;
  8678. if (ctx->type.dataType.IsPrimitive())
  8679. {
  8680. // Load the address of the variable into the register
  8681. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  8682. ctx->type.dataType.MakeReference(true);
  8683. }
  8684. else
  8685. {
  8686. // Push the address of the variable on the stack
  8687. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  8688. // If the object is a value type or a non-handle variable to a reference type,
  8689. // then we must validate the existance as it could potentially be accessed
  8690. // before it is initialized.
  8691. // This check is not needed for application registered properties, since they
  8692. // are guaranteed to be valid by the application itself.
  8693. if (!isAppProp &&
  8694. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8695. !ctx->type.dataType.IsObjectHandle()))
  8696. {
  8697. ctx->bc.Instr(asBC_ChkRefS);
  8698. }
  8699. // If the address pushed on the stack is to a value type or an object
  8700. // handle, then mark the expression as a reference. Addresses to a reference
  8701. // type aren't marked as references to get correct behaviour
  8702. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8703. ctx->type.dataType.IsObjectHandle())
  8704. {
  8705. ctx->type.dataType.MakeReference(true);
  8706. }
  8707. else
  8708. {
  8709. asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle());
  8710. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  8711. ctx->bc.Instr(asBC_RDSPtr);
  8712. }
  8713. }
  8714. }
  8715. return 0;
  8716. }
  8717. if (symbolType == SL_GLOBALFUNC)
  8718. {
  8719. asCArray<int> funcs;
  8720. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8721. asASSERT(funcs.GetLength() > 0);
  8722. if (funcs.GetLength() > 0)
  8723. {
  8724. // Defer the evaluation of which function until it is actually used
  8725. // Store the namespace and name of the function for later
  8726. ctx->type.SetUndefinedFuncHandle(engine);
  8727. ctx->methodName = ns ? ns->name + "::" + name : name;
  8728. }
  8729. return 0;
  8730. }
  8731. if (symbolType == SL_ENUMVAL)
  8732. {
  8733. // The enum type and namespace must be returned from SymbolLookup
  8734. asCDataType dt = lookupResult.type.dataType;
  8735. if (!dt.IsEnumType())
  8736. {
  8737. asASSERT(!engine->ep.requireEnumScope);
  8738. // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known
  8739. ctx->enumValue = name.AddressOf();
  8740. ctx->symbolNamespace = lookupResult.symbolNamespace;
  8741. // We cannot set a dummy value because it will pass through
  8742. // cleanly as an integer.
  8743. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8744. return 0;
  8745. }
  8746. asDWORD value = 0;
  8747. builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
  8748. // Even if the enum type is not shared, and we're compiling a shared object,
  8749. // the use of the values are still allowed, since they are treated as constants.
  8750. // an enum value was resolved
  8751. ctx->type.SetConstantDW(dt, value);
  8752. return 0;
  8753. }
  8754. }
  8755. // The result must have been identified above
  8756. if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE)
  8757. {
  8758. // Give dummy value
  8759. ctx->type.SetDummy();
  8760. // The symbol matches a type
  8761. asCString msg;
  8762. asCString smbl;
  8763. if (scope == "::")
  8764. smbl = scope;
  8765. else if (scope != "")
  8766. smbl = scope + "::";
  8767. smbl += name;
  8768. msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf());
  8769. Error(msg, errNode);
  8770. return -1;
  8771. }
  8772. // Should not come here
  8773. asASSERT(false);
  8774. return 0;
  8775. }
  8776. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  8777. {
  8778. // Shouldn't receive any byte code
  8779. asASSERT(ctx->bc.GetLastInstr() == -1);
  8780. asCScriptNode *vnode = node->firstChild;
  8781. ctx->exprNode = vnode;
  8782. if( vnode->nodeType == snVariableAccess )
  8783. {
  8784. // Determine the scope resolution of the variable
  8785. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  8786. // Determine the name of the variable
  8787. asASSERT(vnode->nodeType == snIdentifier );
  8788. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  8789. return CompileVariableAccess(name, scope, ctx, node);
  8790. }
  8791. else if( vnode->nodeType == snConstant )
  8792. {
  8793. if( vnode->tokenType == ttIntConstant )
  8794. {
  8795. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8796. bool overflow = false;
  8797. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  8798. // Is the number bigger than a 64bit word?
  8799. if (overflow)
  8800. {
  8801. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8802. // Set the value to zero to avoid further warnings
  8803. val = 0;
  8804. }
  8805. // Do we need 64 bits?
  8806. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  8807. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  8808. if( val>>31 )
  8809. {
  8810. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  8811. if( val>>63 )
  8812. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8813. else
  8814. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  8815. }
  8816. else
  8817. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  8818. }
  8819. else if( vnode->tokenType == ttBitsConstant )
  8820. {
  8821. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8822. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  8823. bool overflow = false;
  8824. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  8825. // Is the number bigger than a 64bit word?
  8826. if (overflow)
  8827. {
  8828. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8829. // Set the value to zero to avoid further warnings
  8830. val = 0;
  8831. }
  8832. // Do we need 64 bits?
  8833. if( val>>32 )
  8834. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8835. else
  8836. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  8837. }
  8838. else if( vnode->tokenType == ttFloatConstant )
  8839. {
  8840. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8841. // TODO: Check for overflow
  8842. size_t numScanned;
  8843. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  8844. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  8845. #ifndef AS_USE_DOUBLE_AS_FLOAT
  8846. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  8847. asASSERT(numScanned == vnode->tokenLength - 1);
  8848. #endif
  8849. }
  8850. else if( vnode->tokenType == ttDoubleConstant )
  8851. {
  8852. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8853. // TODO: Check for overflow
  8854. size_t numScanned;
  8855. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  8856. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  8857. asASSERT(numScanned == vnode->tokenLength);
  8858. }
  8859. else if( vnode->tokenType == ttTrue ||
  8860. vnode->tokenType == ttFalse )
  8861. {
  8862. #if AS_SIZEOF_BOOL == 1
  8863. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8864. #else
  8865. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8866. #endif
  8867. }
  8868. else if( vnode->tokenType == ttStringConstant ||
  8869. vnode->tokenType == ttMultilineStringConstant ||
  8870. vnode->tokenType == ttHeredocStringConstant )
  8871. {
  8872. asCString str;
  8873. asCScriptNode *snode = vnode->firstChild;
  8874. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  8875. {
  8876. // Treat the single quoted string as a single character literal
  8877. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8878. asDWORD val = 0;
  8879. if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
  8880. {
  8881. // This is the start of a UTF8 encoded character. We need to decode it
  8882. val = asStringDecodeUTF8(str.AddressOf(), 0);
  8883. if( val == (asDWORD)-1 )
  8884. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8885. }
  8886. else
  8887. {
  8888. val = ProcessStringConstant(str, snode);
  8889. if( val == (asDWORD)-1 )
  8890. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8891. }
  8892. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  8893. }
  8894. else
  8895. {
  8896. // Process the string constants
  8897. while( snode )
  8898. {
  8899. asCString cat;
  8900. if( snode->tokenType == ttStringConstant )
  8901. {
  8902. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8903. ProcessStringConstant(cat, snode);
  8904. }
  8905. else if( snode->tokenType == ttMultilineStringConstant )
  8906. {
  8907. if( !engine->ep.allowMultilineStrings )
  8908. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  8909. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8910. ProcessStringConstant(cat, snode);
  8911. }
  8912. else if( snode->tokenType == ttHeredocStringConstant )
  8913. {
  8914. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  8915. ProcessHeredocStringConstant(cat, snode);
  8916. }
  8917. str += cat;
  8918. snode = snode->next;
  8919. }
  8920. // Call the string factory function to create a string object
  8921. if(engine->stringFactory == 0 )
  8922. {
  8923. // Error
  8924. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  8925. // Give dummy value
  8926. ctx->type.SetDummy();
  8927. return -1;
  8928. }
  8929. else
  8930. {
  8931. void *strPtr = const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
  8932. if (strPtr == 0)
  8933. {
  8934. // TODO: A better message is needed
  8935. Error(TXT_NULL_POINTER_ACCESS, vnode);
  8936. ctx->type.SetDummy();
  8937. return -1;
  8938. }
  8939. // Keep the pointer in the list for clean up at exit
  8940. usedStringConstants.PushLast(strPtr);
  8941. // Push the pointer on the stack. The string factory already guarantees that the
  8942. // string object is valid throughout the lifetime of the script so no need to add
  8943. // reference count or make local copy.
  8944. ctx->bc.InstrPTR(asBC_PGA, strPtr);
  8945. ctx->type.Set(engine->stringType);
  8946. // Mark the string as literal constant so the compiler knows it is allowed
  8947. // to treat it differently than an ordinary constant string variable
  8948. ctx->type.isConstant = true;
  8949. // Mark the reference to the string constant as safe, so the compiler can
  8950. // avoid making unnecessary temporary copies when passing the reference to
  8951. // functions.
  8952. ctx->type.isRefSafe = true;
  8953. }
  8954. }
  8955. }
  8956. else if( vnode->tokenType == ttNull )
  8957. {
  8958. ctx->bc.Instr(asBC_PshNull);
  8959. ctx->type.SetNullConstant();
  8960. }
  8961. else
  8962. asASSERT(false);
  8963. }
  8964. else if( vnode->nodeType == snFunctionCall )
  8965. {
  8966. // Determine the scope resolution
  8967. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  8968. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  8969. }
  8970. else if( vnode->nodeType == snConstructCall )
  8971. {
  8972. return CompileConstructCall(vnode, ctx);
  8973. }
  8974. else if( vnode->nodeType == snAssignment )
  8975. {
  8976. asCExprContext e(engine);
  8977. int r = CompileAssignment(vnode, &e);
  8978. if( r < 0 )
  8979. {
  8980. ctx->type.SetDummy();
  8981. return r;
  8982. }
  8983. MergeExprBytecodeAndType(ctx, &e);
  8984. }
  8985. else if( vnode->nodeType == snCast )
  8986. {
  8987. // Implement the cast operator
  8988. return CompileConversion(vnode, ctx);
  8989. }
  8990. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  8991. {
  8992. // This is a void expression
  8993. ctx->SetVoidExpression();
  8994. }
  8995. else if( vnode->nodeType == snFunction )
  8996. {
  8997. // This is an anonymous function
  8998. // Defer the evaluation of the function until it is known where it
  8999. // will be used, which is where the signature will be defined
  9000. ctx->SetLambda(vnode);
  9001. }
  9002. else
  9003. asASSERT(false);
  9004. return 0;
  9005. }
  9006. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  9007. {
  9008. int charLiteral = -1;
  9009. // Process escape sequences
  9010. asCArray<char> str((int)cstr.GetLength());
  9011. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  9012. {
  9013. #ifdef AS_DOUBLEBYTE_CHARSET
  9014. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  9015. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  9016. {
  9017. // This is the lead character of a double byte character
  9018. // include the trail character without checking it's value.
  9019. str.PushLast(cstr[n]);
  9020. n++;
  9021. str.PushLast(cstr[n]);
  9022. continue;
  9023. }
  9024. #endif
  9025. asUINT val;
  9026. if( processEscapeSequences && cstr[n] == '\\' )
  9027. {
  9028. ++n;
  9029. if( n == cstr.GetLength() )
  9030. {
  9031. if( charLiteral == -1 ) charLiteral = 0;
  9032. return charLiteral;
  9033. }
  9034. // Hexadecimal escape sequences will allow the construction of
  9035. // invalid unicode sequences, but the string should also work as
  9036. // a bytearray so we must support this. The code for working with
  9037. // unicode text must be prepared to handle invalid unicode sequences
  9038. if( cstr[n] == 'x' || cstr[n] == 'X' )
  9039. {
  9040. ++n;
  9041. if( n == cstr.GetLength() ) break;
  9042. val = 0;
  9043. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  9044. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  9045. {
  9046. if( cstr[n] >= '0' && cstr[n] <= '9' )
  9047. val = val*16 + cstr[n] - '0';
  9048. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  9049. val = val*16 + cstr[n] - 'a' + 10;
  9050. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  9051. val = val*16 + cstr[n] - 'A' + 10;
  9052. else
  9053. break;
  9054. }
  9055. // Rewind one, since the loop will increment it again
  9056. n--;
  9057. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  9058. if( engine->ep.stringEncoding == 0 )
  9059. {
  9060. str.PushLast((asBYTE)val);
  9061. }
  9062. else
  9063. {
  9064. #ifndef AS_BIG_ENDIAN
  9065. str.PushLast((asBYTE)val);
  9066. str.PushLast((asBYTE)(val>>8));
  9067. #else
  9068. str.PushLast((asBYTE)(val>>8));
  9069. str.PushLast((asBYTE)val);
  9070. #endif
  9071. }
  9072. if( charLiteral == -1 ) charLiteral = val;
  9073. continue;
  9074. }
  9075. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  9076. {
  9077. // \u expects 4 hex digits
  9078. // \U expects 8 hex digits
  9079. bool expect2 = cstr[n] == 'u';
  9080. int c = expect2 ? 4 : 8;
  9081. val = 0;
  9082. for( ; c > 0; c-- )
  9083. {
  9084. ++n;
  9085. if( n == cstr.GetLength() ) break;
  9086. if( cstr[n] >= '0' && cstr[n] <= '9' )
  9087. val = val*16 + cstr[n] - '0';
  9088. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  9089. val = val*16 + cstr[n] - 'a' + 10;
  9090. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  9091. val = val*16 + cstr[n] - 'A' + 10;
  9092. else
  9093. break;
  9094. }
  9095. if( c != 0 )
  9096. {
  9097. // Give warning about invalid code point
  9098. // TODO: Need code position for warning
  9099. asCString msg;
  9100. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  9101. Warning(msg, node);
  9102. continue;
  9103. }
  9104. }
  9105. else
  9106. {
  9107. if( cstr[n] == '"' )
  9108. val = '"';
  9109. else if( cstr[n] == '\'' )
  9110. val = '\'';
  9111. else if( cstr[n] == 'n' )
  9112. val = '\n';
  9113. else if( cstr[n] == 'r' )
  9114. val = '\r';
  9115. else if( cstr[n] == 't' )
  9116. val = '\t';
  9117. else if( cstr[n] == '0' )
  9118. val = '\0';
  9119. else if( cstr[n] == '\\' )
  9120. val = '\\';
  9121. else
  9122. {
  9123. // Invalid escape sequence
  9124. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  9125. continue;
  9126. }
  9127. }
  9128. }
  9129. else
  9130. {
  9131. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  9132. {
  9133. unsigned int len;
  9134. val = asStringDecodeUTF8(&cstr[n], &len);
  9135. if( val == 0xFFFFFFFF )
  9136. {
  9137. // Incorrect UTF8 encoding. Use only the first byte
  9138. // TODO: Need code position for warning
  9139. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  9140. val = (unsigned char)cstr[n];
  9141. }
  9142. else
  9143. n += len-1;
  9144. }
  9145. else
  9146. val = (unsigned char)cstr[n];
  9147. }
  9148. // Add the character to the final string
  9149. char encodedValue[5];
  9150. int len;
  9151. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  9152. {
  9153. // Convert to UTF8 encoded
  9154. len = asStringEncodeUTF8(val, encodedValue);
  9155. }
  9156. else if( engine->ep.stringEncoding == 1 )
  9157. {
  9158. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  9159. len = asStringEncodeUTF16(val, encodedValue);
  9160. }
  9161. else
  9162. {
  9163. // Do not convert ASCII characters
  9164. encodedValue[0] = (asBYTE)val;
  9165. len = 1;
  9166. }
  9167. if( len < 0 )
  9168. {
  9169. // Give warning about invalid code point
  9170. // TODO: Need code position for warning
  9171. Warning(TXT_INVALID_UNICODE_VALUE, node);
  9172. }
  9173. else
  9174. {
  9175. // Add the encoded value to the final string
  9176. str.Concatenate(encodedValue, len);
  9177. if( charLiteral == -1 ) charLiteral = val;
  9178. }
  9179. }
  9180. cstr.Assign(str.AddressOf(), str.GetLength());
  9181. return charLiteral;
  9182. }
  9183. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  9184. {
  9185. // Remove first line if it only contains whitespace
  9186. bool isMultiline = false;
  9187. int start;
  9188. for( start = 0; start < (int)str.GetLength(); start++ )
  9189. {
  9190. if( str[start] == '\n' )
  9191. {
  9192. isMultiline = true;
  9193. // Remove the linebreak as well
  9194. start++;
  9195. break;
  9196. }
  9197. if( str[start] != ' ' &&
  9198. str[start] != '\t' &&
  9199. str[start] != '\r' )
  9200. {
  9201. // Don't remove anything
  9202. start = 0;
  9203. break;
  9204. }
  9205. }
  9206. // Remove the line after the last line break if it only contains whitespaces
  9207. int end;
  9208. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  9209. {
  9210. if( str[end] == '\n' )
  9211. {
  9212. // Don't remove the last line break
  9213. end++;
  9214. break;
  9215. }
  9216. if( str[end] != ' ' &&
  9217. str[end] != '\t' &&
  9218. str[end] != '\r' )
  9219. {
  9220. // Don't remove anything
  9221. end = (int)str.GetLength();
  9222. break;
  9223. }
  9224. }
  9225. if( end < 0 ) end = 0;
  9226. asCString tmp;
  9227. if (end > start || engine->ep.heredocTrimMode != 2 )
  9228. {
  9229. // if heredocTrimMode == 0 the string shouldn't be trimmed
  9230. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  9231. // if heredocTrimMode == 2 the string should always be trimmed
  9232. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  9233. tmp.Assign(&str[start], end - start);
  9234. else
  9235. tmp = str;
  9236. }
  9237. ProcessStringConstant(tmp, node, false);
  9238. str = tmp;
  9239. }
  9240. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  9241. {
  9242. asCExprContext expr(engine);
  9243. asCDataType to;
  9244. bool anyErrors = false;
  9245. EImplicitConv convType;
  9246. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  9247. {
  9248. convType = asIC_EXPLICIT_VAL_CAST;
  9249. // Verify that there is only one argument
  9250. if( node->lastChild->firstChild == 0 ||
  9251. node->lastChild->firstChild != node->lastChild->lastChild )
  9252. {
  9253. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  9254. expr.type.SetDummy();
  9255. anyErrors = true;
  9256. }
  9257. else if (node->lastChild->firstChild &&
  9258. node->lastChild->firstChild->nodeType == snNamedArgument)
  9259. {
  9260. Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
  9261. expr.type.SetDummy();
  9262. anyErrors = true;
  9263. }
  9264. else
  9265. {
  9266. // Compile the expression
  9267. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  9268. if( r < 0 )
  9269. anyErrors = true;
  9270. }
  9271. // Determine the requested type
  9272. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9273. to.MakeReadOnly(true); // Default to const
  9274. asASSERT(to.IsPrimitive());
  9275. }
  9276. else
  9277. {
  9278. convType = asIC_EXPLICIT_REF_CAST;
  9279. // Compile the expression
  9280. int r = CompileAssignment(node->lastChild, &expr);
  9281. if( r < 0 )
  9282. anyErrors = true;
  9283. // Determine the requested type
  9284. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9285. // If the type support object handles, then use it
  9286. if( to.SupportHandles() )
  9287. {
  9288. to.MakeHandle(true);
  9289. if( expr.type.dataType.IsObjectConst() )
  9290. to.MakeHandleToConst(true);
  9291. }
  9292. else if( !to.IsObjectHandle() )
  9293. {
  9294. // The cast<type> operator can only be used for reference casts
  9295. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  9296. anyErrors = true;
  9297. }
  9298. }
  9299. // Do not allow casting to non shared type if we're compiling a shared method
  9300. if( outFunc->IsShared() &&
  9301. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  9302. {
  9303. asCString msg;
  9304. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  9305. Error(msg, node);
  9306. anyErrors = true;
  9307. }
  9308. if( anyErrors )
  9309. {
  9310. // Assume that the error can be fixed and allow the compilation to continue
  9311. ctx->type.Set(to);
  9312. return -1;
  9313. }
  9314. if( ProcessPropertyGetAccessor(&expr, node) < 0 )
  9315. return -1;
  9316. // Don't allow any operators on expressions that take address of class method
  9317. if( expr.IsClassMethod() )
  9318. {
  9319. Error(TXT_INVALID_OP_ON_METHOD, node);
  9320. return -1;
  9321. }
  9322. // We don't want a reference for conversion casts
  9323. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  9324. {
  9325. if( expr.type.dataType.IsObject() )
  9326. Dereference(&expr, true);
  9327. else
  9328. ConvertToVariable(&expr);
  9329. }
  9330. ImplicitConversion(&expr, to, node, convType);
  9331. IsVariableInitialized(&expr.type, node);
  9332. // If no type conversion is really tried ignore it
  9333. if( to == expr.type.dataType )
  9334. {
  9335. // This will keep information about constant type
  9336. MergeExprBytecode(ctx, &expr);
  9337. ctx->type = expr.type;
  9338. return 0;
  9339. }
  9340. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  9341. {
  9342. MergeExprBytecode(ctx, &expr);
  9343. ctx->type = expr.type;
  9344. ctx->type.dataType.MakeReadOnly(true);
  9345. return 0;
  9346. }
  9347. // The implicit conversion already does most of the conversions permitted,
  9348. // here we'll only treat those conversions that require an explicit cast.
  9349. bool conversionOK = false;
  9350. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  9351. {
  9352. if( !expr.type.dataType.IsObject() )
  9353. ConvertToTempVariable(&expr);
  9354. if( to.IsObjectHandle() &&
  9355. expr.type.dataType.IsObjectHandle() &&
  9356. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  9357. {
  9358. conversionOK = CompileRefCast(&expr, to, true, node);
  9359. MergeExprBytecode(ctx, &expr);
  9360. ctx->type = expr.type;
  9361. }
  9362. }
  9363. if( conversionOK )
  9364. return 0;
  9365. // Conversion not available
  9366. ctx->type.SetDummy();
  9367. asCString strTo, strFrom;
  9368. strTo = to.Format(outFunc->nameSpace);
  9369. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  9370. asCString msg;
  9371. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  9372. Error(msg, node);
  9373. return -1;
  9374. }
  9375. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  9376. {
  9377. // deferAll is set to true if for example the function returns a reference, since in
  9378. // this case the function might be returning a reference to one of the arguments.
  9379. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  9380. // Parameters that are sent by reference should be assigned
  9381. // to the evaluated expression if it is an lvalue
  9382. // Evaluate the arguments from last to first
  9383. int n = (int)descr->parameterTypes.GetLength() - 1;
  9384. for( ; n >= 0; n-- )
  9385. {
  9386. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  9387. // If deferAll is set all objects passed by reference or handle must be deferred
  9388. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  9389. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  9390. {
  9391. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  9392. // For &inout, only store the argument if it is for a temporary variable
  9393. if( engine->ep.allowUnsafeReferences ||
  9394. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  9395. {
  9396. // Store the argument for later processing
  9397. asSDeferredParam outParam;
  9398. outParam.argNode = args[n]->exprNode;
  9399. outParam.argType = args[n]->type;
  9400. outParam.argInOutFlags = descr->inOutFlags[n];
  9401. outParam.origExpr = args[n]->origExpr;
  9402. ctx->deferredParams.PushLast(outParam);
  9403. }
  9404. }
  9405. else
  9406. {
  9407. // Release the temporary variable now
  9408. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  9409. }
  9410. // Move the argument's deferred expressions over to the final expression
  9411. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  9412. {
  9413. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  9414. args[n]->deferredParams[m].origExpr = 0;
  9415. }
  9416. args[n]->deferredParams.SetLength(0);
  9417. }
  9418. }
  9419. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  9420. {
  9421. if( isProcessingDeferredParams ) return;
  9422. isProcessingDeferredParams = true;
  9423. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  9424. {
  9425. asSDeferredParam outParam = ctx->deferredParams[n];
  9426. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  9427. {
  9428. // Just release the variable
  9429. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9430. }
  9431. else if( outParam.argInOutFlags == asTM_OUTREF )
  9432. {
  9433. asCExprContext *expr = outParam.origExpr;
  9434. outParam.origExpr = 0;
  9435. if( outParam.argType.dataType.IsObjectHandle() )
  9436. {
  9437. // Implicitly convert the value to a handle
  9438. if( expr->type.dataType.IsObjectHandle() )
  9439. expr->type.isExplicitHandle = true;
  9440. }
  9441. // Verify that the expression result in a lvalue, or a property accessor
  9442. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  9443. {
  9444. asCExprContext rctx(engine);
  9445. rctx.type = outParam.argType;
  9446. if( rctx.type.dataType.IsPrimitive() )
  9447. rctx.type.dataType.MakeReference(false);
  9448. else
  9449. {
  9450. rctx.bc.InstrSHORT(asBC_PSF, (short)outParam.argType.stackOffset);
  9451. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  9452. if( expr->type.isExplicitHandle )
  9453. rctx.type.isExplicitHandle = true;
  9454. }
  9455. asCExprContext o(engine);
  9456. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  9457. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  9458. // The assignment may itself have resulted in a new temporary variable, e.g. if
  9459. // the opAssign returns a non-reference. We must release this temporary variable
  9460. // since it won't be used
  9461. ReleaseTemporaryVariable(o.type, &o.bc);
  9462. MergeExprBytecode(ctx, &o);
  9463. }
  9464. else
  9465. {
  9466. // We must still evaluate the expression
  9467. MergeExprBytecode(ctx, expr);
  9468. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  9469. ctx->bc.Instr(asBC_PopPtr);
  9470. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  9471. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() &&
  9472. !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) )
  9473. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  9474. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9475. }
  9476. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  9477. // Delete the original expression context
  9478. asDELETE(expr, asCExprContext);
  9479. }
  9480. else // &inout
  9481. {
  9482. if( outParam.argType.isTemporary )
  9483. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9484. else if( !outParam.argType.isVariable )
  9485. {
  9486. if( outParam.argType.dataType.IsObject() && !outParam.argType.IsNullConstant() &&
  9487. ((outParam.argType.dataType.GetBehaviour()->addref &&
  9488. outParam.argType.dataType.GetBehaviour()->release) ||
  9489. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  9490. {
  9491. // Release the object handle that was taken to guarantee the reference
  9492. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9493. }
  9494. }
  9495. }
  9496. }
  9497. ctx->deferredParams.SetLength(0);
  9498. isProcessingDeferredParams = false;
  9499. }
  9500. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  9501. {
  9502. // The first node is a datatype node
  9503. asCString name;
  9504. asCExprValue tempObj;
  9505. bool onHeap = true;
  9506. asCArray<int> funcs;
  9507. bool error = false;
  9508. // It is possible that the name is really a constructor
  9509. asCDataType dt;
  9510. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  9511. if( dt.IsPrimitive() )
  9512. {
  9513. // This is a cast to a primitive type
  9514. return CompileConversion(node, ctx);
  9515. }
  9516. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  9517. {
  9518. // Types declared as implicit handle must not attempt to construct a handle
  9519. dt.MakeHandle(false);
  9520. }
  9521. // Don't accept syntax like object@(expr)
  9522. if( dt.IsObjectHandle() )
  9523. {
  9524. asCString str;
  9525. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  9526. Error(str, node);
  9527. ctx->type.SetDummy();
  9528. return -1;
  9529. }
  9530. // Make sure the desired type can actually be instantiated
  9531. // Delegates are allowed to be created through construct calls,
  9532. // even though they cannot be instantiated as variables
  9533. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  9534. {
  9535. asCString str;
  9536. if( dt.IsAbstractClass() )
  9537. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9538. else if( dt.IsInterface() )
  9539. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9540. else
  9541. // TODO: Improve error message to explain why
  9542. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  9543. Error(str, node);
  9544. ctx->type.SetDummy();
  9545. return -1;
  9546. }
  9547. // Do not allow constructing non-shared types in shared functions
  9548. if( outFunc->IsShared() &&
  9549. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  9550. {
  9551. asCString msg;
  9552. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  9553. Error(msg, node);
  9554. return -1;
  9555. }
  9556. // Compile the arguments
  9557. asCArray<asCExprContext *> args;
  9558. asCArray<asSNamedArgument> namedArgs;
  9559. asCArray<asCExprValue> temporaryVariables;
  9560. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9561. {
  9562. // Check for a value cast behaviour
  9563. if( args.GetLength() == 1 )
  9564. {
  9565. asCExprContext conv(engine);
  9566. conv.Copy(args[0]);
  9567. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  9568. // Clean the property_arg in the temporary copy so
  9569. // it isn't deleted when conv goes out of scope
  9570. conv.property_arg = 0;
  9571. // Don't use this if the cost is 0 because it would mean that nothing
  9572. // is done and the script wants a new value to be constructed
  9573. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  9574. {
  9575. // Make sure the result is a reference, just as if to a local variable
  9576. if( !dt.IsFuncdef() )
  9577. dt.MakeReference(true);
  9578. // Make sure any property accessor is already evaluated
  9579. if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 )
  9580. return -1;
  9581. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  9582. MergeExprBytecode(ctx, args[0]);
  9583. ctx->type = args[0]->type;
  9584. asDELETE(args[0], asCExprContext);
  9585. return 0;
  9586. }
  9587. }
  9588. // Check for possible constructor/factory
  9589. name = dt.Format(outFunc->nameSpace);
  9590. asSTypeBehaviour *beh = dt.GetBehaviour();
  9591. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  9592. {
  9593. funcs = beh->constructors;
  9594. // Value types and script types are allocated through the constructor
  9595. tempObj.dataType = dt;
  9596. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  9597. tempObj.dataType.MakeReference(true);
  9598. tempObj.isTemporary = true;
  9599. tempObj.isVariable = true;
  9600. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  9601. // Push the address of the object on the stack
  9602. if( onHeap )
  9603. ctx->bc.InstrSHORT(asBC_VAR, (short)tempObj.stackOffset);
  9604. }
  9605. else if( beh )
  9606. funcs = beh->factories;
  9607. // Special case: Allow calling func(void) with a void expression.
  9608. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  9609. {
  9610. // Evaluate the expression before the function call
  9611. MergeExprBytecode(ctx, args[0]);
  9612. asDELETE(args[0], asCExprContext);
  9613. args.SetLength(0);
  9614. }
  9615. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  9616. // If none has been registered, just allocate the variable and push it on the stack.
  9617. if( args.GetLength() == 0 )
  9618. {
  9619. beh = tempObj.dataType.GetBehaviour();
  9620. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9621. {
  9622. // Call the default constructor
  9623. ctx->type = tempObj;
  9624. if( onHeap )
  9625. {
  9626. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  9627. ctx->bc.RemoveLastInstr();
  9628. }
  9629. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  9630. // Push the reference on the stack
  9631. ctx->bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  9632. return 0;
  9633. }
  9634. }
  9635. // Special case: If this is a construction of a delegate and the expression names an object method
  9636. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  9637. {
  9638. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  9639. // case no object delegate will be created, but instead a delegate for a function pointer
  9640. // In theory a simple cast would be good in this case, but this is a construct call so it
  9641. // is expected that a new object is created.
  9642. dt.MakeHandle(true);
  9643. ctx->type.Set(dt);
  9644. // The delegate must be able to hold on to a reference to the object
  9645. if( !args[0]->type.dataType.SupportHandles() )
  9646. {
  9647. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  9648. error = true;
  9649. }
  9650. else
  9651. {
  9652. // Filter the available object methods to find the one that matches the func def
  9653. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  9654. asCScriptFunction *bestMethod = 0;
  9655. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  9656. {
  9657. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  9658. if( func->name != args[0]->methodName )
  9659. continue;
  9660. // If the expression is for a const object, then only const methods should be accepted
  9661. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  9662. continue;
  9663. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  9664. {
  9665. bestMethod = func;
  9666. // If the expression is non-const the non-const overloaded method has priority
  9667. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  9668. break;
  9669. }
  9670. }
  9671. if( bestMethod )
  9672. {
  9673. // The object pointer is already on the stack
  9674. MergeExprBytecode(ctx, args[0]);
  9675. // Push the function pointer as an additional argument
  9676. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  9677. // Call the factory function for the delegate
  9678. asCArray<int> delegateFuncs;
  9679. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  9680. asASSERT(delegateFuncs.GetLength() == 1 );
  9681. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  9682. // Store the returned delegate in a temporary variable
  9683. int returnOffset = AllocateVariable(dt, true, false);
  9684. dt.MakeReference(true);
  9685. ctx->type.SetVariable(dt, returnOffset, true);
  9686. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9687. // Push a reference to the temporary variable on the stack
  9688. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9689. // Clean up arguments
  9690. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  9691. }
  9692. else
  9693. {
  9694. asCString msg;
  9695. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  9696. Error(msg.AddressOf(), node);
  9697. error = true;
  9698. }
  9699. }
  9700. // Clean-up arg
  9701. asDELETE(args[0], asCExprContext);
  9702. return error ? -1 : 0;
  9703. }
  9704. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  9705. if( funcs.GetLength() != 1 )
  9706. {
  9707. // The error was reported by MatchFunctions()
  9708. error = true;
  9709. // Dummy value
  9710. ctx->type.SetDummy();
  9711. }
  9712. else
  9713. {
  9714. // TODO: Clean up: Merge this with MakeFunctionCall
  9715. // Add the default values for arguments not explicitly supplied
  9716. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  9717. if( r == asSUCCESS )
  9718. {
  9719. asCByteCode objBC(engine);
  9720. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  9721. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  9722. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9723. {
  9724. // If the object is allocated on the stack, then call the constructor as a normal function
  9725. if( onHeap )
  9726. {
  9727. int offset = 0;
  9728. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  9729. for( asUINT n = 0; n < args.GetLength(); n++ )
  9730. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  9731. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  9732. }
  9733. else
  9734. ctx->bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  9735. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  9736. // Add tag that the object has been initialized
  9737. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  9738. // The constructor doesn't return anything,
  9739. // so we have to manually inform the type of
  9740. // the return value
  9741. ctx->type = tempObj;
  9742. if( !onHeap )
  9743. ctx->type.dataType.MakeReference(false);
  9744. // Push the address of the object on the stack again
  9745. ctx->bc.InstrSHORT(asBC_PSF, (short)tempObj.stackOffset);
  9746. }
  9747. else
  9748. {
  9749. // Call the factory to create the reference type
  9750. PerformFunctionCall(funcs[0], ctx, false, &args);
  9751. }
  9752. }
  9753. else
  9754. error = true;
  9755. }
  9756. }
  9757. else
  9758. {
  9759. // Failed to compile the argument list, set the result to the dummy type
  9760. ctx->type.SetDummy();
  9761. error = true;
  9762. }
  9763. // Cleanup
  9764. for( asUINT n = 0; n < args.GetLength(); n++ )
  9765. if( args[n] )
  9766. {
  9767. asDELETE(args[n], asCExprContext);
  9768. }
  9769. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9770. if( namedArgs[n].ctx )
  9771. {
  9772. asDELETE(namedArgs[n].ctx, asCExprContext);
  9773. }
  9774. return error ? -1 : 0;
  9775. }
  9776. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  9777. {
  9778. asCExprValue tempObj;
  9779. asCArray<int> funcs;
  9780. int localVar = -1;
  9781. bool initializeMembers = false;
  9782. asCExprContext funcExpr(engine);
  9783. asCScriptNode *nm = node->lastChild->prev;
  9784. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  9785. // Find the matching entities
  9786. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  9787. asCExprContext lookupResult(engine);
  9788. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult);
  9789. if (symbolType < 0)
  9790. return -1;
  9791. if (symbolType == SL_NOMATCH)
  9792. {
  9793. // No matching symbol
  9794. asCString msg;
  9795. asCString smbl;
  9796. if (scope == "::")
  9797. smbl = scope;
  9798. else if (scope != "")
  9799. smbl = scope + "::";
  9800. smbl += name;
  9801. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  9802. Error(msg, node);
  9803. return -1;
  9804. }
  9805. // Is the symbol matching a variable/property?
  9806. if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ||
  9807. symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP ||
  9808. symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL)
  9809. {
  9810. // Variables/properties can be used as functions if they have the opCall
  9811. // Compile the variable
  9812. // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
  9813. localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
  9814. if( localVar < 0 )
  9815. return -1;
  9816. if (funcExpr.type.dataType.IsFuncdef())
  9817. {
  9818. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  9819. }
  9820. else if (funcExpr.type.dataType.IsObject())
  9821. {
  9822. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  9823. if (ctx->type.isTemporary)
  9824. {
  9825. asASSERT(objectType);
  9826. asSDeferredParam deferred;
  9827. deferred.origExpr = 0;
  9828. deferred.argInOutFlags = asTM_INREF;
  9829. deferred.argNode = 0;
  9830. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9831. ctx->deferredParams.PushLast(deferred);
  9832. }
  9833. if (funcExpr.property_get == 0)
  9834. Dereference(ctx, true);
  9835. // Add the bytecode for accessing the object on which opCall will be called
  9836. if (ctx->type.dataType.IsObject())
  9837. {
  9838. // Make sure the ProcessPropertyGetAccess knows whether or not to
  9839. // dereference the original object before calling the get accessor
  9840. funcExpr.property_ref = ctx->type.dataType.IsReference();
  9841. }
  9842. MergeExprBytecodeAndType(ctx, &funcExpr);
  9843. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  9844. return -1;
  9845. Dereference(ctx, true);
  9846. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  9847. // Get the opCall methods from the object type
  9848. if (funcExpr.type.dataType.IsObjectHandle())
  9849. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  9850. else
  9851. objIsConst = funcExpr.type.dataType.IsReadOnly();
  9852. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  9853. }
  9854. else
  9855. {
  9856. // The variable is not a function or object with opCall
  9857. asCString msg;
  9858. msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf());
  9859. Error(msg, node);
  9860. return -1;
  9861. }
  9862. }
  9863. // Is the symbol matching a class method?
  9864. if (symbolType == SL_CLASSMETHOD)
  9865. {
  9866. // If we're compiling a constructor and the name of the function is super then
  9867. // the constructor of the base class is being called.
  9868. // super cannot be prefixed with a scope operator
  9869. if (scope == "" && m_isConstructor && name == SUPER_TOKEN)
  9870. {
  9871. // If the class is not derived from anyone else, calling super should give an error
  9872. if (outFunc && outFunc->objectType->derivedFrom)
  9873. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  9874. // Must not allow calling base class' constructor multiple times
  9875. if (continueLabels.GetLength() > 0)
  9876. {
  9877. // If a continue label is set we are in a loop
  9878. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  9879. }
  9880. else if (breakLabels.GetLength() > 0)
  9881. {
  9882. // TODO: inheritance: Should eventually allow constructors in switch statements
  9883. // If a break label is set we are either in a loop or a switch statements
  9884. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  9885. }
  9886. else if (m_isConstructorCalled)
  9887. {
  9888. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  9889. }
  9890. m_isConstructorCalled = true;
  9891. // We need to initialize the class members, but only after all the deferred arguments have been completed
  9892. initializeMembers = true;
  9893. }
  9894. else
  9895. {
  9896. // The scope can be used to specify the base class
  9897. builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script);
  9898. }
  9899. // If a class method is being called implicitly, then add the this pointer for the call
  9900. if (funcs.GetLength() && !objectType && outFunc->objectType)
  9901. {
  9902. // Verify that the identified function is actually part of the class hierarchy
  9903. if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
  9904. {
  9905. asCString msg;
  9906. asCString mthd;
  9907. if (scope == "")
  9908. mthd = name;
  9909. else if (scope == "::")
  9910. mthd = scope + name;
  9911. else
  9912. mthd = scope + "::" + name;
  9913. msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf());
  9914. Error(msg, node);
  9915. return -1;
  9916. }
  9917. objectType = outFunc->objectType;
  9918. asCDataType dt = asCDataType::CreateType(objectType, false);
  9919. // The object pointer is located at stack position 0
  9920. ctx->bc.InstrSHORT(asBC_PSF, 0);
  9921. ctx->type.SetVariable(dt, 0, false);
  9922. ctx->type.dataType.MakeReference(true);
  9923. Dereference(ctx, true);
  9924. }
  9925. else if (funcs.GetLength() && !objectType && !outFunc->objectType)
  9926. {
  9927. // Cannot call class methods directly without the object
  9928. asCString msg;
  9929. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  9930. Error(msg, node);
  9931. return -1;
  9932. }
  9933. }
  9934. // Is it a global function?
  9935. if (symbolType == SL_GLOBALFUNC)
  9936. {
  9937. // The symbol lookup identified the namespace to use
  9938. int n = lookupResult.methodName.FindLast("::");
  9939. asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf());
  9940. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  9941. }
  9942. // Is it a type?
  9943. if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE)
  9944. {
  9945. bool isValid = false;
  9946. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid);
  9947. if (isValid)
  9948. return CompileConstructCall(node, ctx);
  9949. }
  9950. // Compile the arguments
  9951. asCArray<asCExprContext *> args;
  9952. asCArray<asSNamedArgument> namedArgs;
  9953. bool isOK = true;
  9954. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9955. {
  9956. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  9957. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  9958. {
  9959. // Evaluate the expression before the function call
  9960. MergeExprBytecode(ctx, args[0]);
  9961. asDELETE(args[0], asCExprContext);
  9962. args.SetLength(0);
  9963. }
  9964. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  9965. if( funcs.GetLength() != 1 )
  9966. {
  9967. // The error was reported by MatchFunctions()
  9968. // Dummy value
  9969. ctx->type.SetDummy();
  9970. isOK = false;
  9971. }
  9972. else
  9973. {
  9974. // Add the default values for arguments not explicitly supplied
  9975. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  9976. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9977. // is it enough to make sure it is in a local variable?
  9978. // For function pointer we must guarantee that the function is safe, i.e.
  9979. // by first storing the function pointer in a local variable (if it isn't already in one)
  9980. if( r == asSUCCESS )
  9981. {
  9982. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  9983. if( func->funcType == asFUNC_FUNCDEF )
  9984. {
  9985. if( objectType && funcExpr.property_get <= 0 )
  9986. {
  9987. // Dereference the object pointer to access the member
  9988. Dereference(ctx, true);
  9989. }
  9990. if( funcExpr.property_get > 0 )
  9991. {
  9992. if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 )
  9993. return -1;
  9994. Dereference(&funcExpr, true);
  9995. }
  9996. else
  9997. {
  9998. Dereference(&funcExpr, true);
  9999. ConvertToVariable(&funcExpr);
  10000. }
  10001. // The actual function should be called as if a global function
  10002. objectType = 0;
  10003. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  10004. funcExpr.bc.Instr(asBC_PopPtr);
  10005. asCExprValue tmp = ctx->type;
  10006. MergeExprBytecodeAndType(ctx, &funcExpr);
  10007. ReleaseTemporaryVariable(tmp, &ctx->bc);
  10008. }
  10009. r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  10010. if( r < 0 )
  10011. {
  10012. ctx->type.SetDummy();
  10013. isOK = false;
  10014. }
  10015. }
  10016. else
  10017. isOK = false;
  10018. }
  10019. }
  10020. else
  10021. {
  10022. // Failed to compile the argument list, set the dummy type and continue compilation
  10023. ctx->type.SetDummy();
  10024. isOK = false;
  10025. }
  10026. // Cleanup
  10027. for( asUINT n = 0; n < args.GetLength(); n++ )
  10028. if( args[n] )
  10029. {
  10030. asDELETE(args[n], asCExprContext);
  10031. }
  10032. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  10033. if( namedArgs[n].ctx )
  10034. {
  10035. asDELETE(namedArgs[n].ctx, asCExprContext);
  10036. }
  10037. if( initializeMembers )
  10038. {
  10039. asASSERT( m_isConstructor );
  10040. // Need to initialize members here, as they may use the properties of the base class
  10041. // If there are multiple paths that call super(), then there will also be multiple
  10042. // locations with initializations of the members. It is not possible to consolidate
  10043. // these in one place, as the expressions for the initialization are evaluated where
  10044. // they are compiled, which means that they may access different variables depending
  10045. // on the scope where super() is called.
  10046. // Members that don't have an explicit initialization expression will be initialized
  10047. // beginning of the constructor as they are guaranteed not to use at the any
  10048. // members of the base class.
  10049. CompileMemberInitialization(&ctx->bc, false);
  10050. }
  10051. return isOK ? 0 : -1;
  10052. }
  10053. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  10054. {
  10055. asSNameSpace *ns;
  10056. if( scope == "" )
  10057. {
  10058. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  10059. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  10060. ns = outFunc->nameSpace;
  10061. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  10062. ns = outFunc->objectType->nameSpace;
  10063. else
  10064. ns = engine->nameSpaces[0];
  10065. }
  10066. else if( scope == "::" )
  10067. ns = engine->nameSpaces[0];
  10068. else
  10069. ns = engine->FindNameSpace(scope.AddressOf());
  10070. return ns;
  10071. }
  10072. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  10073. {
  10074. int op = node->tokenType;
  10075. // Don't allow any prefix operators except handle on expressions that take address of class method
  10076. if( ctx->IsClassMethod() && op != ttHandle )
  10077. {
  10078. Error(TXT_INVALID_OP_ON_METHOD, node);
  10079. return -1;
  10080. }
  10081. // Don't allow any operators on void expressions
  10082. if( ctx->IsVoidExpression() )
  10083. {
  10084. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10085. return -1;
  10086. }
  10087. IsVariableInitialized(&ctx->type, node);
  10088. if( op == ttHandle )
  10089. {
  10090. if( ctx->methodName != "" )
  10091. {
  10092. // Don't allow taking the handle of a handle
  10093. if( ctx->type.isExplicitHandle )
  10094. {
  10095. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10096. return -1;
  10097. }
  10098. }
  10099. else
  10100. {
  10101. // Don't allow taking handle of a handle, i.e. @@
  10102. if( ctx->type.isExplicitHandle )
  10103. {
  10104. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10105. return -1;
  10106. }
  10107. // @null is allowed even though it is implicit
  10108. if( !ctx->type.IsNullConstant() )
  10109. {
  10110. // Verify that the type allow its handle to be taken
  10111. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  10112. {
  10113. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10114. return -1;
  10115. }
  10116. // Objects that are not local variables are not references
  10117. // Objects allocated on the stack are also not marked as references
  10118. if( !ctx->type.dataType.IsReference() &&
  10119. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  10120. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  10121. {
  10122. Error(TXT_NOT_VALID_REFERENCE, node);
  10123. return -1;
  10124. }
  10125. // Convert the expression to a handle
  10126. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  10127. {
  10128. asCDataType to = ctx->type.dataType;
  10129. to.MakeHandle(true);
  10130. to.MakeReference(true);
  10131. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  10132. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  10133. asASSERT( ctx->type.dataType.IsObjectHandle() );
  10134. }
  10135. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  10136. {
  10137. // For the ASHANDLE type we'll simply set the expression as a handle
  10138. ctx->type.dataType.MakeHandle(true);
  10139. }
  10140. }
  10141. }
  10142. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  10143. ctx->type.isExplicitHandle = true;
  10144. }
  10145. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10146. {
  10147. // Look for the appropriate method
  10148. // There is no overloadable operator for unary plus
  10149. const char *opName = 0;
  10150. switch( op )
  10151. {
  10152. case ttMinus: opName = "opNeg"; break;
  10153. case ttBitNot: opName = "opCom"; break;
  10154. case ttInc: opName = "opPreInc"; break;
  10155. case ttDec: opName = "opPreDec"; break;
  10156. }
  10157. if( opName )
  10158. {
  10159. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10160. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10161. return -1;
  10162. // 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
  10163. // Find the correct method
  10164. bool isConst = ctx->type.dataType.IsObjectConst();
  10165. asCArray<int> funcs;
  10166. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10167. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10168. {
  10169. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10170. if( func->name == opName &&
  10171. func->parameterTypes.GetLength() == 0 &&
  10172. (!isConst || func->IsReadOnly()) )
  10173. {
  10174. funcs.PushLast(func->id);
  10175. }
  10176. }
  10177. // Did we find the method?
  10178. if( funcs.GetLength() == 1 )
  10179. {
  10180. asCArray<asCExprContext *> args;
  10181. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10182. }
  10183. else if( funcs.GetLength() == 0 )
  10184. {
  10185. asCString str;
  10186. str = asCString(opName) + "()";
  10187. if( isConst )
  10188. str += " const";
  10189. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10190. Error(str, node);
  10191. ctx->type.SetDummy();
  10192. return -1;
  10193. }
  10194. else if( funcs.GetLength() > 1 )
  10195. {
  10196. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10197. PrintMatchingFuncs(funcs, node);
  10198. ctx->type.SetDummy();
  10199. return -1;
  10200. }
  10201. }
  10202. else if( op == ttPlus )
  10203. {
  10204. Error(TXT_ILLEGAL_OPERATION, node);
  10205. ctx->type.SetDummy();
  10206. return -1;
  10207. }
  10208. }
  10209. else if( op == ttPlus || op == ttMinus )
  10210. {
  10211. // This is only for primitives. Objects are treated in the above block
  10212. // Make sure the type is a math type
  10213. if( !(ctx->type.dataType.IsIntegerType() ||
  10214. ctx->type.dataType.IsUnsignedType() ||
  10215. ctx->type.dataType.IsFloatType() ||
  10216. ctx->type.dataType.IsDoubleType() ) )
  10217. {
  10218. Error(TXT_ILLEGAL_OPERATION, node);
  10219. return -1;
  10220. }
  10221. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10222. return -1;
  10223. asCDataType to = ctx->type.dataType;
  10224. if( ctx->type.dataType.IsUnsignedType() )
  10225. {
  10226. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10227. to = asCDataType::CreatePrimitive(ttInt8, false);
  10228. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10229. to = asCDataType::CreatePrimitive(ttInt16, false);
  10230. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10231. to = asCDataType::CreatePrimitive(ttInt, false);
  10232. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10233. to = asCDataType::CreatePrimitive(ttInt64, false);
  10234. else
  10235. {
  10236. Error(TXT_INVALID_TYPE, node);
  10237. return -1;
  10238. }
  10239. }
  10240. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10241. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  10242. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  10243. if( !ctx->type.isConstant )
  10244. {
  10245. ConvertToTempVariable(ctx);
  10246. asASSERT(!ctx->type.isLValue);
  10247. if( op == ttMinus )
  10248. {
  10249. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10250. ctx->bc.InstrSHORT(asBC_NEGi, (short)ctx->type.stackOffset);
  10251. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10252. ctx->bc.InstrSHORT(asBC_NEGi64, (short)ctx->type.stackOffset);
  10253. else if( ctx->type.dataType.IsFloatType() )
  10254. ctx->bc.InstrSHORT(asBC_NEGf, (short)ctx->type.stackOffset);
  10255. else if( ctx->type.dataType.IsDoubleType() )
  10256. ctx->bc.InstrSHORT(asBC_NEGd, (short)ctx->type.stackOffset);
  10257. else
  10258. {
  10259. Error(TXT_ILLEGAL_OPERATION, node);
  10260. return -1;
  10261. }
  10262. return 0;
  10263. }
  10264. }
  10265. else
  10266. {
  10267. if( op == ttMinus )
  10268. {
  10269. if (ctx->type.dataType.IsIntegerType())
  10270. {
  10271. if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10272. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  10273. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10274. ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
  10275. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
  10276. ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
  10277. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
  10278. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  10279. }
  10280. else if( ctx->type.dataType.IsFloatType() )
  10281. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  10282. else if( ctx->type.dataType.IsDoubleType() )
  10283. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  10284. else
  10285. {
  10286. Error(TXT_ILLEGAL_OPERATION, node);
  10287. return -1;
  10288. }
  10289. return 0;
  10290. }
  10291. }
  10292. }
  10293. else if( op == ttNot )
  10294. {
  10295. // Allow value types to be converted to bool using 'bool opImplConv()'
  10296. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  10297. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  10298. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  10299. {
  10300. if( ctx->type.isConstant )
  10301. {
  10302. #if AS_SIZEOF_BOOL == 1
  10303. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10304. #else
  10305. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10306. #endif
  10307. return 0;
  10308. }
  10309. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10310. return -1;
  10311. ConvertToTempVariable(ctx);
  10312. asASSERT(!ctx->type.isLValue);
  10313. ctx->bc.InstrSHORT(asBC_NOT, (short)ctx->type.stackOffset);
  10314. }
  10315. else
  10316. {
  10317. Error(TXT_ILLEGAL_OPERATION, node);
  10318. return -1;
  10319. }
  10320. }
  10321. else if( op == ttBitNot )
  10322. {
  10323. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10324. return -1;
  10325. asCDataType to = ctx->type.dataType;
  10326. if( ctx->type.dataType.IsIntegerType() )
  10327. {
  10328. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10329. to = asCDataType::CreatePrimitive(ttUInt8, false);
  10330. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10331. to = asCDataType::CreatePrimitive(ttUInt16, false);
  10332. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10333. to = asCDataType::CreatePrimitive(ttUInt, false);
  10334. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10335. to = asCDataType::CreatePrimitive(ttUInt64, false);
  10336. else
  10337. {
  10338. Error(TXT_INVALID_TYPE, node);
  10339. return -1;
  10340. }
  10341. }
  10342. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10343. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  10344. if( ctx->type.dataType.IsUnsignedType() )
  10345. {
  10346. if( ctx->type.isConstant )
  10347. {
  10348. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10349. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  10350. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10351. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  10352. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10353. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  10354. else
  10355. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  10356. return 0;
  10357. }
  10358. ConvertToTempVariable(ctx);
  10359. asASSERT(!ctx->type.isLValue);
  10360. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10361. ctx->bc.InstrSHORT(asBC_BNOT, (short)ctx->type.stackOffset);
  10362. else
  10363. ctx->bc.InstrSHORT(asBC_BNOT64, (short)ctx->type.stackOffset);
  10364. }
  10365. else
  10366. {
  10367. Error(TXT_ILLEGAL_OPERATION, node);
  10368. return -1;
  10369. }
  10370. }
  10371. else if( op == ttInc || op == ttDec )
  10372. {
  10373. // Need a reference to the primitive that will be updated
  10374. // The result of this expression is the same reference as before
  10375. // Make sure the reference isn't a temporary variable
  10376. if( ctx->type.isTemporary )
  10377. {
  10378. Error(TXT_REF_IS_TEMP, node);
  10379. return -1;
  10380. }
  10381. if( ctx->type.dataType.IsReadOnly() )
  10382. {
  10383. Error(TXT_REF_IS_READ_ONLY, node);
  10384. return -1;
  10385. }
  10386. if( ctx->property_get || ctx->property_set )
  10387. {
  10388. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10389. return -1;
  10390. }
  10391. if( !ctx->type.isLValue )
  10392. {
  10393. Error(TXT_NOT_LVALUE, node);
  10394. return -1;
  10395. }
  10396. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10397. ConvertToReference(ctx);
  10398. else if( !ctx->type.dataType.IsReference() )
  10399. {
  10400. Error(TXT_NOT_VALID_REFERENCE, node);
  10401. return -1;
  10402. }
  10403. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10404. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10405. {
  10406. if( op == ttInc )
  10407. ctx->bc.Instr(asBC_INCi64);
  10408. else
  10409. ctx->bc.Instr(asBC_DECi64);
  10410. }
  10411. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  10412. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  10413. {
  10414. if( op == ttInc )
  10415. ctx->bc.Instr(asBC_INCi);
  10416. else
  10417. ctx->bc.Instr(asBC_DECi);
  10418. }
  10419. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10420. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10421. {
  10422. if( op == ttInc )
  10423. ctx->bc.Instr(asBC_INCi16);
  10424. else
  10425. ctx->bc.Instr(asBC_DECi16);
  10426. }
  10427. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10428. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10429. {
  10430. if( op == ttInc )
  10431. ctx->bc.Instr(asBC_INCi8);
  10432. else
  10433. ctx->bc.Instr(asBC_DECi8);
  10434. }
  10435. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  10436. {
  10437. if( op == ttInc )
  10438. ctx->bc.Instr(asBC_INCf);
  10439. else
  10440. ctx->bc.Instr(asBC_DECf);
  10441. }
  10442. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  10443. {
  10444. if( op == ttInc )
  10445. ctx->bc.Instr(asBC_INCd);
  10446. else
  10447. ctx->bc.Instr(asBC_DECd);
  10448. }
  10449. else
  10450. {
  10451. Error(TXT_ILLEGAL_OPERATION, node);
  10452. return -1;
  10453. }
  10454. }
  10455. else
  10456. {
  10457. // Unknown operator
  10458. asASSERT(false);
  10459. return -1;
  10460. }
  10461. return 0;
  10462. }
  10463. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  10464. {
  10465. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10466. {
  10467. ctx->bc.InstrSHORT(asBC_LDV, (short)ctx->type.stackOffset);
  10468. ctx->type.dataType.MakeReference(true);
  10469. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  10470. }
  10471. }
  10472. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10473. {
  10474. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  10475. }
  10476. // Returns:
  10477. // 1 = a valid match was found
  10478. // 0 = no matching symbols (or feature disabled)
  10479. // -1 = ambiguous getters or setters, i.e. multiple methods match symbol name and signature
  10480. // -2 = mismatching type for getter and setter
  10481. // -3 = processing error, e.g. out of memory
  10482. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10483. {
  10484. // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the
  10485. // getter/setter as it is done at the time of declaration. Should deprecate the other options
  10486. if( engine->ep.propertyAccessorMode == 0 )
  10487. {
  10488. // Property accessors have been disabled by the application
  10489. return 0;
  10490. }
  10491. int getId = 0, setId = 0;
  10492. asCString getName = "get_" + name;
  10493. asCString setName = "set_" + name;
  10494. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  10495. if( ctx->type.dataType.IsObject() )
  10496. {
  10497. asASSERT( ns == 0 );
  10498. // Don't look for property accessors in script classes if the script
  10499. // property accessors have been disabled by the application
  10500. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  10501. engine->ep.propertyAccessorMode >= 2 )
  10502. {
  10503. // Check if the object has any methods with the corresponding accessor name(s)
  10504. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10505. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10506. {
  10507. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  10508. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10509. continue;
  10510. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10511. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10512. {
  10513. if( getId == 0 )
  10514. getId = ot->methods[n];
  10515. else
  10516. {
  10517. if( multipleGetFuncs.GetLength() == 0 )
  10518. multipleGetFuncs.PushLast(getId);
  10519. multipleGetFuncs.PushLast(ot->methods[n]);
  10520. }
  10521. }
  10522. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10523. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10524. {
  10525. if( setId == 0 )
  10526. setId = ot->methods[n];
  10527. else
  10528. {
  10529. if( multipleSetFuncs.GetLength() == 0 )
  10530. multipleSetFuncs.PushLast(setId);
  10531. multipleSetFuncs.PushLast(ot->methods[n]);
  10532. }
  10533. }
  10534. }
  10535. }
  10536. }
  10537. else
  10538. {
  10539. asASSERT( ns != 0 );
  10540. // Look for appropriate global functions.
  10541. asCArray<int> funcs;
  10542. asUINT n;
  10543. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  10544. for( n = 0; n < funcs.GetLength(); n++ )
  10545. {
  10546. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10547. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10548. continue;
  10549. // Ignore script functions, if the application has disabled script defined property accessors
  10550. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10551. continue;
  10552. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10553. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10554. {
  10555. if( getId == 0 )
  10556. getId = funcs[n];
  10557. else
  10558. {
  10559. if( multipleGetFuncs.GetLength() == 0 )
  10560. multipleGetFuncs.PushLast(getId);
  10561. multipleGetFuncs.PushLast(funcs[n]);
  10562. }
  10563. }
  10564. }
  10565. funcs.SetLength(0);
  10566. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  10567. for( n = 0; n < funcs.GetLength(); n++ )
  10568. {
  10569. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10570. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10571. continue;
  10572. // Ignore script functions, if the application has disabled script defined property accessors
  10573. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10574. continue;
  10575. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10576. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10577. {
  10578. if( setId == 0 )
  10579. setId = funcs[n];
  10580. else
  10581. {
  10582. if( multipleSetFuncs.GetLength() == 0 )
  10583. multipleSetFuncs.PushLast(setId);
  10584. multipleSetFuncs.PushLast(funcs[n]);
  10585. }
  10586. }
  10587. }
  10588. }
  10589. bool isConst = ctx->type.dataType.IsObjectConst();
  10590. // Check for multiple matches
  10591. if( multipleGetFuncs.GetLength() > 0 )
  10592. {
  10593. // Filter the list by constness
  10594. FilterConst(multipleGetFuncs, !isConst);
  10595. if( multipleGetFuncs.GetLength() > 1 )
  10596. {
  10597. if (node)
  10598. {
  10599. asCString str;
  10600. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  10601. Error(str, node);
  10602. PrintMatchingFuncs(multipleGetFuncs, node);
  10603. }
  10604. return -1;
  10605. }
  10606. else
  10607. {
  10608. // The id may have changed
  10609. getId = multipleGetFuncs[0];
  10610. }
  10611. }
  10612. if( multipleSetFuncs.GetLength() > 0 )
  10613. {
  10614. // Filter the list by constness
  10615. FilterConst(multipleSetFuncs, !isConst);
  10616. if( multipleSetFuncs.GetLength() > 1 )
  10617. {
  10618. if (node)
  10619. {
  10620. asCString str;
  10621. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  10622. Error(str, node);
  10623. PrintMatchingFuncs(multipleSetFuncs, node);
  10624. }
  10625. return -1;
  10626. }
  10627. else
  10628. {
  10629. // The id may have changed
  10630. setId = multipleSetFuncs[0];
  10631. }
  10632. }
  10633. // Check for type compatibility between get and set accessor
  10634. if( getId && setId )
  10635. {
  10636. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  10637. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  10638. // It is permitted for a getter to return a handle and the setter to take a reference
  10639. int idx = (arg?1:0);
  10640. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  10641. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  10642. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  10643. {
  10644. if (node)
  10645. {
  10646. asCString str;
  10647. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  10648. Error(str, node);
  10649. asCArray<int> funcs;
  10650. funcs.PushLast(getId);
  10651. funcs.PushLast(setId);
  10652. PrintMatchingFuncs(funcs, node);
  10653. }
  10654. return -2;
  10655. }
  10656. }
  10657. // Check if we are within one of the accessors
  10658. int realGetId = getId;
  10659. int realSetId = setId;
  10660. if( outFunc->objectType && isThisAccess )
  10661. {
  10662. // The property accessors would be virtual functions, so we need to find the real implementation
  10663. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  10664. if( getFunc &&
  10665. getFunc->funcType == asFUNC_VIRTUAL &&
  10666. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  10667. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  10668. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  10669. if( setFunc &&
  10670. setFunc->funcType == asFUNC_VIRTUAL &&
  10671. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  10672. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  10673. }
  10674. // Avoid recursive call by not treating this as a property accessor call.
  10675. // This will also allow having the real property with the same name as the accessors.
  10676. if( (isThisAccess || outFunc->objectType == 0) &&
  10677. ((realGetId && realGetId == outFunc->id) ||
  10678. (realSetId && realSetId == outFunc->id)) )
  10679. {
  10680. getId = 0;
  10681. setId = 0;
  10682. }
  10683. if( getId || setId )
  10684. {
  10685. // Property accessors were found, but we don't know which is to be used yet, so
  10686. // we just prepare the bytecode for the method call, and then store the function ids
  10687. // so that the right one can be used when we get there.
  10688. ctx->property_get = getId;
  10689. ctx->property_set = setId;
  10690. bool isRefSafe = ctx->type.isRefSafe;
  10691. if( ctx->type.dataType.IsObject() )
  10692. {
  10693. // If the object is read-only then we need to remember that
  10694. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  10695. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  10696. ctx->property_const = true;
  10697. else
  10698. ctx->property_const = false;
  10699. // If the object is a handle then we need to remember that
  10700. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  10701. ctx->property_ref = ctx->type.dataType.IsReference();
  10702. }
  10703. // The setter's parameter type is used as the property type,
  10704. // unless only the getter is available
  10705. asCDataType dt;
  10706. if( setId )
  10707. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  10708. else
  10709. dt = builder->GetFunctionDescription(getId)->returnType;
  10710. // Just change the type, the context must still maintain information
  10711. // about previous variable offset and the indicator of temporary variable.
  10712. int offset = ctx->type.stackOffset;
  10713. bool isTemp = ctx->type.isTemporary;
  10714. ctx->type.Set(dt);
  10715. ctx->type.stackOffset = (short)offset;
  10716. ctx->type.isTemporary = isTemp;
  10717. ctx->exprNode = node;
  10718. // Remember if the object is safe, so the invocation of the property
  10719. // accessor doesn't needlessly make a safe copy of the handle
  10720. ctx->type.isRefSafe = isRefSafe;
  10721. // Store the argument for later use
  10722. if( arg )
  10723. {
  10724. ctx->property_arg = asNEW(asCExprContext)(engine);
  10725. if( ctx->property_arg == 0 )
  10726. {
  10727. // Out of memory
  10728. return -3;
  10729. }
  10730. MergeExprBytecodeAndType(ctx->property_arg, arg);
  10731. }
  10732. return 1;
  10733. }
  10734. // No accessor was found
  10735. return 0;
  10736. }
  10737. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  10738. {
  10739. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  10740. if( !ctx->property_set )
  10741. {
  10742. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  10743. return -1;
  10744. }
  10745. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  10746. // Make sure the arg match the property
  10747. asCArray<int> funcs;
  10748. funcs.PushLast(ctx->property_set);
  10749. asCArray<asCExprContext *> args;
  10750. if( ctx->property_arg )
  10751. args.PushLast(ctx->property_arg);
  10752. args.PushLast(arg);
  10753. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10754. if( funcs.GetLength() == 0 )
  10755. {
  10756. // MatchFunctions already reported the error
  10757. if( ctx->property_arg )
  10758. {
  10759. asDELETE(ctx->property_arg, asCExprContext);
  10760. ctx->property_arg = 0;
  10761. }
  10762. return -1;
  10763. }
  10764. if( func->objectType )
  10765. {
  10766. // Setup the context with the original type so the method call gets built correctly
  10767. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10768. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10769. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10770. // Don't allow the call if the object is read-only and the property accessor is not const
  10771. if( ctx->property_const && !func->IsReadOnly() )
  10772. {
  10773. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10774. asCArray<int> funcCandidates;
  10775. funcCandidates.PushLast(ctx->property_set);
  10776. PrintMatchingFuncs(funcCandidates, node);
  10777. }
  10778. }
  10779. // Call the accessor
  10780. int r = MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  10781. ctx->property_get = 0;
  10782. ctx->property_set = 0;
  10783. if( ctx->property_arg )
  10784. {
  10785. asDELETE(ctx->property_arg, asCExprContext);
  10786. ctx->property_arg = 0;
  10787. }
  10788. return r;
  10789. }
  10790. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  10791. {
  10792. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  10793. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  10794. // to support value types, since it would be a single call
  10795. // Compound assignment for indexed property accessors is not supported yet
  10796. if( lctx->property_arg != 0 )
  10797. {
  10798. // Process the property to free the memory
  10799. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10800. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  10801. return -1;
  10802. }
  10803. // Compound assignments require both get and set accessors
  10804. if( lctx->property_set == 0 || lctx->property_get == 0 )
  10805. {
  10806. // Process the property to free the memory
  10807. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10808. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  10809. return -1;
  10810. }
  10811. // Property accessors on value types (or scoped references types) are not supported since
  10812. // it is not possible to guarantee that the object will stay alive between the two calls
  10813. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  10814. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  10815. {
  10816. // Process the property to free the memory
  10817. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10818. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  10819. return -1;
  10820. }
  10821. // Translate the compound assignment to the corresponding dual operator
  10822. switch( op )
  10823. {
  10824. case ttAddAssign: op = ttPlus; break;
  10825. case ttSubAssign: op = ttMinus; break;
  10826. case ttMulAssign: op = ttStar; break;
  10827. case ttDivAssign: op = ttSlash; break;
  10828. case ttModAssign: op = ttPercent; break;
  10829. case ttPowAssign: op = ttStarStar; break;
  10830. case ttAndAssign: op = ttAmp; break;
  10831. case ttOrAssign: op = ttBitOr; break;
  10832. case ttXorAssign: op = ttBitXor; break;
  10833. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  10834. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  10835. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  10836. default: op = ttUnrecognizedToken; break;
  10837. }
  10838. if( op == ttUnrecognizedToken )
  10839. {
  10840. // Shouldn't happen
  10841. asASSERT(false);
  10842. // Process the property to free the memory
  10843. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10844. return -1;
  10845. }
  10846. asCExprContext before(engine);
  10847. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  10848. {
  10849. // Keep a reference to the object in a local variable
  10850. before.bc.AddCode(&lctx->bc);
  10851. asUINT len = reservedVariables.GetLength();
  10852. rctx->bc.GetVarsUsed(reservedVariables);
  10853. before.bc.GetVarsUsed(reservedVariables);
  10854. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  10855. int offset = AllocateVariable(dt, true);
  10856. reservedVariables.SetLength(len);
  10857. before.type.SetVariable(dt, offset, true);
  10858. if( lctx->property_ref )
  10859. before.bc.Instr(asBC_RDSPtr);
  10860. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  10861. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  10862. before.bc.Instr(asBC_PopPtr);
  10863. if( lctx->type.isTemporary )
  10864. {
  10865. // Add the release of the temporary variable as a deferred expression
  10866. asSDeferredParam deferred;
  10867. deferred.origExpr = 0;
  10868. deferred.argInOutFlags = asTM_INREF;
  10869. deferred.argNode = 0;
  10870. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  10871. before.deferredParams.PushLast(deferred);
  10872. }
  10873. // Update the left expression to use the local variable
  10874. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10875. lctx->type.stackOffset = (short)offset;
  10876. lctx->property_ref = true;
  10877. // Don't release the temporary variable too early
  10878. lctx->type.isTemporary = false;
  10879. ctx->bc.AddCode(&before.bc);
  10880. }
  10881. // Keep the original information on the property
  10882. asCExprContext llctx(engine);
  10883. llctx.type = lctx->type;
  10884. llctx.property_arg = lctx->property_arg;
  10885. llctx.property_const = lctx->property_const;
  10886. llctx.property_get = lctx->property_get;
  10887. llctx.property_handle = lctx->property_handle;
  10888. llctx.property_ref = lctx->property_ref;
  10889. llctx.property_set = lctx->property_set;
  10890. // Compile the dual operator using the get accessor
  10891. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  10892. // If we made a local variable to hold the reference it must be reused
  10893. if( before.type.stackOffset )
  10894. llctx.bc.InstrSHORT(asBC_PSF, (short)before.type.stackOffset);
  10895. // Compile the assignment using the set accessor
  10896. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  10897. MergeExprBytecodeAndType(ctx, &llctx);
  10898. if( before.type.stackOffset )
  10899. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  10900. asASSERT( ctx->deferredParams.GetLength() == 0 );
  10901. ctx->deferredParams = before.deferredParams;
  10902. ProcessDeferredParams(ctx);
  10903. return 0;
  10904. }
  10905. int asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  10906. {
  10907. // If no property accessor has been prepared then don't do anything
  10908. if( !ctx->property_get && !ctx->property_set )
  10909. return 0;
  10910. if( !ctx->property_get )
  10911. {
  10912. // Raise error on missing accessor
  10913. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  10914. return -1;
  10915. }
  10916. asCExprValue objType = ctx->type;
  10917. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  10918. // Make sure the arg match the property
  10919. asCArray<int> funcs;
  10920. funcs.PushLast(ctx->property_get);
  10921. asCArray<asCExprContext *> args;
  10922. if( ctx->property_arg )
  10923. args.PushLast(ctx->property_arg);
  10924. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10925. if( funcs.GetLength() == 0 )
  10926. {
  10927. // MatchFunctions already reported the error
  10928. if( ctx->property_arg )
  10929. {
  10930. asDELETE(ctx->property_arg, asCExprContext);
  10931. ctx->property_arg = 0;
  10932. }
  10933. return -1;
  10934. }
  10935. if( func->objectType )
  10936. {
  10937. // Setup the context with the original type so the method call gets built correctly
  10938. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10939. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10940. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10941. // Don't allow the call if the object is read-only and the property accessor is not const
  10942. if( ctx->property_const && !func->IsReadOnly() )
  10943. {
  10944. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10945. asCArray<int> funcCandidates;
  10946. funcCandidates.PushLast(ctx->property_get);
  10947. PrintMatchingFuncs(funcCandidates, node);
  10948. return -1;
  10949. }
  10950. }
  10951. // The explicit handle flag must be remembered
  10952. bool isExplicitHandle = ctx->type.isExplicitHandle;
  10953. // Call the accessor
  10954. int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  10955. if( isExplicitHandle )
  10956. ctx->type.isExplicitHandle = true;
  10957. // Clear the property get/set ids
  10958. ctx->property_get = 0;
  10959. ctx->property_set = 0;
  10960. if( ctx->property_arg )
  10961. {
  10962. asDELETE(ctx->property_arg, asCExprContext);
  10963. ctx->property_arg = 0;
  10964. }
  10965. return r;
  10966. }
  10967. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  10968. {
  10969. // Don't allow any postfix operators on expressions that take address of class method
  10970. if( ctx->IsClassMethod() )
  10971. {
  10972. Error(TXT_INVALID_OP_ON_METHOD, node);
  10973. return -1;
  10974. }
  10975. // Don't allow any operators on void expressions
  10976. if( ctx->IsVoidExpression() )
  10977. {
  10978. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10979. return -1;
  10980. }
  10981. // Check if the variable is initialized (if it indeed is a variable)
  10982. IsVariableInitialized(&ctx->type, node);
  10983. int op = node->tokenType;
  10984. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10985. {
  10986. const char *opName = 0;
  10987. switch( op )
  10988. {
  10989. case ttInc: opName = "opPostInc"; break;
  10990. case ttDec: opName = "opPostDec"; break;
  10991. }
  10992. if( opName )
  10993. {
  10994. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10995. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10996. return -1;
  10997. // 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
  10998. // Find the correct method
  10999. bool isConst = ctx->type.dataType.IsObjectConst();
  11000. asCArray<int> funcs;
  11001. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11002. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  11003. {
  11004. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11005. if( func->name == opName &&
  11006. func->parameterTypes.GetLength() == 0 &&
  11007. (!isConst || func->IsReadOnly()) )
  11008. {
  11009. funcs.PushLast(func->id);
  11010. }
  11011. }
  11012. // Did we find the method?
  11013. if( funcs.GetLength() == 1 )
  11014. {
  11015. asCArray<asCExprContext *> args;
  11016. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  11017. }
  11018. else if( funcs.GetLength() == 0 )
  11019. {
  11020. asCString str;
  11021. str = asCString(opName) + "()";
  11022. if( isConst )
  11023. str += " const";
  11024. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  11025. Error(str, node);
  11026. ctx->type.SetDummy();
  11027. return -1;
  11028. }
  11029. else if( funcs.GetLength() > 1 )
  11030. {
  11031. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11032. PrintMatchingFuncs(funcs, node);
  11033. ctx->type.SetDummy();
  11034. return -1;
  11035. }
  11036. }
  11037. }
  11038. else if( op == ttInc || op == ttDec )
  11039. {
  11040. // Make sure the reference isn't a temporary variable
  11041. if( ctx->type.isTemporary )
  11042. {
  11043. Error(TXT_REF_IS_TEMP, node);
  11044. return -1;
  11045. }
  11046. if( ctx->type.dataType.IsReadOnly() )
  11047. {
  11048. Error(TXT_REF_IS_READ_ONLY, node);
  11049. return -1;
  11050. }
  11051. if( ctx->property_get || ctx->property_set )
  11052. {
  11053. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  11054. return -1;
  11055. }
  11056. if( !ctx->type.isLValue )
  11057. {
  11058. Error(TXT_NOT_LVALUE, node);
  11059. return -1;
  11060. }
  11061. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  11062. ConvertToReference(ctx);
  11063. else if( !ctx->type.dataType.IsReference() )
  11064. {
  11065. Error(TXT_NOT_VALID_REFERENCE, node);
  11066. return -1;
  11067. }
  11068. // Copy the value to a temp before changing it
  11069. ConvertToTempVariable(ctx);
  11070. asASSERT(!ctx->type.isLValue);
  11071. // Increment the value pointed to by the reference still in the register
  11072. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  11073. if( ctx->type.dataType.IsDoubleType() )
  11074. {
  11075. iInc = asBC_INCd;
  11076. iDec = asBC_DECd;
  11077. }
  11078. else if( ctx->type.dataType.IsFloatType() )
  11079. {
  11080. iInc = asBC_INCf;
  11081. iDec = asBC_DECf;
  11082. }
  11083. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  11084. {
  11085. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  11086. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  11087. {
  11088. iInc = asBC_INCi16;
  11089. iDec = asBC_DECi16;
  11090. }
  11091. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  11092. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  11093. {
  11094. iInc = asBC_INCi8;
  11095. iDec = asBC_DECi8;
  11096. }
  11097. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  11098. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  11099. {
  11100. iInc = asBC_INCi64;
  11101. iDec = asBC_DECi64;
  11102. }
  11103. }
  11104. else
  11105. {
  11106. Error(TXT_ILLEGAL_OPERATION, node);
  11107. return -1;
  11108. }
  11109. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  11110. }
  11111. else if( op == ttDot )
  11112. {
  11113. if( node->firstChild->nodeType == snIdentifier )
  11114. {
  11115. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11116. return -1;
  11117. // Get the property name
  11118. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  11119. if( ctx->type.dataType.IsObject() )
  11120. {
  11121. // We need to look for get/set property accessors.
  11122. // If found, the context stores information on the get/set accessors
  11123. // until it is known which is to be used.
  11124. int r = 0;
  11125. if( node->next && node->next->tokenType == ttOpenBracket )
  11126. {
  11127. // The property accessor should take an index arg
  11128. asCExprContext dummyArg(engine);
  11129. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  11130. }
  11131. if( r == 0 )
  11132. r = FindPropertyAccessor(name, ctx, node, 0);
  11133. if( r != 0 )
  11134. return r;
  11135. if( !ctx->type.dataType.IsPrimitive() )
  11136. Dereference(ctx, true);
  11137. if( ctx->type.dataType.IsObjectHandle() )
  11138. {
  11139. // Convert the handle to a normal object
  11140. asCDataType dt = ctx->type.dataType;
  11141. dt.MakeHandle(false);
  11142. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  11143. // The handle may not have been an lvalue, but the dereferenced object is
  11144. ctx->type.isLValue = true;
  11145. }
  11146. bool isConst = ctx->type.dataType.IsObjectConst();
  11147. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  11148. if( prop )
  11149. {
  11150. // Is the property access allowed?
  11151. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  11152. {
  11153. asCString msg;
  11154. if( prop->isPrivate )
  11155. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  11156. else
  11157. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  11158. Error(msg, node);
  11159. }
  11160. // Adjust the pointer for composite member
  11161. // 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
  11162. if( prop->compositeOffset || prop->isCompositeIndirect )
  11163. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11164. if (prop->isCompositeIndirect)
  11165. ctx->bc.Instr(asBC_RDSPtr);
  11166. // Put the offset on the stack
  11167. // This must always be done even if the offset is 0 so the type info is stored
  11168. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11169. if( prop->type.IsReference() )
  11170. ctx->bc.Instr(asBC_RDSPtr);
  11171. // Reference to primitive must be stored in the temp register
  11172. if( prop->type.IsPrimitive() )
  11173. {
  11174. ctx->bc.Instr(asBC_PopRPtr);
  11175. }
  11176. // Keep information about temporary variables as deferred expression
  11177. if( ctx->type.isTemporary )
  11178. {
  11179. // Add the release of this reference, as a deferred expression
  11180. asSDeferredParam deferred;
  11181. deferred.origExpr = 0;
  11182. deferred.argInOutFlags = asTM_INREF;
  11183. deferred.argNode = 0;
  11184. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  11185. ctx->deferredParams.PushLast(deferred);
  11186. }
  11187. // Set the new type and make sure it is not treated as a variable anymore
  11188. ctx->type.dataType = prop->type;
  11189. ctx->type.dataType.MakeReference(true);
  11190. ctx->type.isVariable = false;
  11191. ctx->type.isTemporary = false;
  11192. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  11193. {
  11194. // Objects that are members are not references
  11195. ctx->type.dataType.MakeReference(false);
  11196. // The object is safe (life time guaranteed) if the parent object is also safe
  11197. }
  11198. else if (ctx->type.dataType.IsObjectHandle())
  11199. {
  11200. // A object accessed through a handle cannot be considered safe,
  11201. // as it can be cleared at any time
  11202. ctx->type.isRefSafe = false;
  11203. }
  11204. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  11205. }
  11206. else
  11207. {
  11208. // If the name is not a property, the compiler must check if the name matches
  11209. // a method, which can be used for constructing delegates
  11210. asIScriptFunction *func = 0;
  11211. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11212. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  11213. {
  11214. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  11215. {
  11216. func = engine->scriptFunctions[ot->methods[n]];
  11217. break;
  11218. }
  11219. }
  11220. if( func )
  11221. {
  11222. // An object method was found. Keep the name of the method in the expression, but
  11223. // don't actually modify the bytecode at this point since it is not yet known what
  11224. // the method will be used for, or even what overloaded method should be used.
  11225. ctx->methodName = name;
  11226. }
  11227. else
  11228. {
  11229. asCString str;
  11230. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11231. Error(str, node);
  11232. return -1;
  11233. }
  11234. }
  11235. }
  11236. else
  11237. {
  11238. asCString str;
  11239. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11240. Error(str, node);
  11241. return -1;
  11242. }
  11243. }
  11244. else
  11245. {
  11246. // Make sure it is an object we are accessing
  11247. if( !ctx->type.dataType.IsObject() )
  11248. {
  11249. asCString str;
  11250. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11251. Error(str, node);
  11252. return -1;
  11253. }
  11254. // Process the get property accessor
  11255. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11256. return -1;
  11257. // Compile function call
  11258. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  11259. if( r < 0 ) return r;
  11260. }
  11261. }
  11262. else if( op == ttOpenBracket )
  11263. {
  11264. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  11265. // then we should use that instead of processing it now. If the argument has already been
  11266. // evaluated, then we should process the property accessor as a get access now as the new
  11267. // index operator is on the result of that accessor.
  11268. asCString propertyName;
  11269. asSNameSpace *ns = 0;
  11270. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  11271. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  11272. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  11273. {
  11274. // Determine the name of the property accessor
  11275. asCScriptFunction *func = 0;
  11276. if( ctx->property_get )
  11277. func = builder->GetFunctionDescription(ctx->property_get);
  11278. else
  11279. func = builder->GetFunctionDescription(ctx->property_set);
  11280. propertyName = func->GetName();
  11281. propertyName = propertyName.SubString(4);
  11282. // Set the original type of the expression so we can re-evaluate the property accessor
  11283. if( func->objectType )
  11284. {
  11285. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  11286. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  11287. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  11288. }
  11289. else
  11290. {
  11291. // Store the namespace where the function is declared
  11292. // so the same function can be found later
  11293. ctx->type.SetDummy();
  11294. ns = func->nameSpace;
  11295. }
  11296. ctx->property_get = ctx->property_set = 0;
  11297. if( ctx->property_arg )
  11298. {
  11299. asDELETE(ctx->property_arg, asCExprContext);
  11300. ctx->property_arg = 0;
  11301. }
  11302. }
  11303. else
  11304. {
  11305. if( !ctx->type.dataType.IsObject() )
  11306. {
  11307. asCString str;
  11308. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11309. Error(str, node);
  11310. return -1;
  11311. }
  11312. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11313. return -1;
  11314. }
  11315. // Compile the expression
  11316. bool isOK = true;
  11317. asCArray<asCExprContext *> args;
  11318. asCArray<asSNamedArgument> namedArgs;
  11319. asASSERT( node->firstChild->nodeType == snArgList );
  11320. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  11321. {
  11322. // Check for the existence of the opIndex method
  11323. bool lookForProperty = true;
  11324. if( propertyName == "" )
  11325. {
  11326. bool isConst = ctx->type.dataType.IsObjectConst();
  11327. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11328. asCArray<int> funcs;
  11329. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  11330. if( funcs.GetLength() > 0 )
  11331. {
  11332. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  11333. lookForProperty = false;
  11334. // Determine which of opIndex methods that match
  11335. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  11336. if( funcs.GetLength() != 1 )
  11337. {
  11338. // The error has already been reported by MatchFunctions
  11339. isOK = false;
  11340. }
  11341. else
  11342. {
  11343. // Add the default values for arguments not explicitly supplied
  11344. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  11345. if( r < 0 )
  11346. isOK = false;
  11347. else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 )
  11348. isOK = false;
  11349. }
  11350. }
  11351. }
  11352. if( lookForProperty && isOK )
  11353. {
  11354. if( args.GetLength() != 1 )
  11355. {
  11356. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  11357. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  11358. isOK = false;
  11359. }
  11360. else
  11361. {
  11362. Dereference(ctx, true);
  11363. asCExprContext lctx(engine);
  11364. MergeExprBytecodeAndType(&lctx, ctx);
  11365. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  11366. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  11367. if (r == 0)
  11368. {
  11369. asCString str;
  11370. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11371. Error(str, node);
  11372. isOK = false;
  11373. }
  11374. else if (r < 0)
  11375. isOK = false;
  11376. if (isOK)
  11377. MergeExprBytecodeAndType(ctx, &lctx);
  11378. }
  11379. }
  11380. }
  11381. else
  11382. isOK = false;
  11383. // Cleanup
  11384. for( asUINT n = 0; n < args.GetLength(); n++ )
  11385. if( args[n] )
  11386. {
  11387. asDELETE(args[n], asCExprContext);
  11388. }
  11389. if( !isOK )
  11390. return -1;
  11391. }
  11392. else if( op == ttOpenParenthesis )
  11393. {
  11394. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  11395. // Make sure the expression is a funcdef or an object that may have opCall methods
  11396. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  11397. {
  11398. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  11399. return -1;
  11400. }
  11401. // Compile arguments
  11402. bool isOK = true;
  11403. asCArray<asCExprContext *> args;
  11404. asCArray<asSNamedArgument> namedArgs;
  11405. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  11406. {
  11407. // Match arguments with the funcdef
  11408. asCArray<int> funcs;
  11409. if( ctx->type.dataType.IsFuncdef() )
  11410. {
  11411. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  11412. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  11413. }
  11414. else
  11415. {
  11416. bool isConst = ctx->type.dataType.IsObjectConst();
  11417. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  11418. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  11419. }
  11420. if( funcs.GetLength() != 1 )
  11421. {
  11422. // The error was reported by MatchFunctions()
  11423. // Dummy value
  11424. ctx->type.SetDummy();
  11425. }
  11426. else
  11427. {
  11428. // Add the default values for arguments not explicitly supplied
  11429. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  11430. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  11431. // is it enough to make sure it is in a local variable?
  11432. // For function pointer we must guarantee that the function is safe, i.e.
  11433. // by first storing the function pointer in a local variable (if it isn't already in one)
  11434. if( r == asSUCCESS )
  11435. {
  11436. Dereference(ctx, true);
  11437. if( ctx->type.dataType.IsFuncdef() )
  11438. {
  11439. if( !ctx->type.isVariable )
  11440. ConvertToVariable(ctx);
  11441. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  11442. ctx->bc.Instr(asBC_PopPtr);
  11443. }
  11444. r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  11445. if( r < 0 )
  11446. isOK = false;
  11447. }
  11448. else
  11449. isOK = false;
  11450. }
  11451. }
  11452. else
  11453. ctx->type.SetDummy();
  11454. // Cleanup
  11455. for( asUINT n = 0; n < args.GetLength(); n++ )
  11456. if( args[n] )
  11457. {
  11458. asDELETE(args[n], asCExprContext);
  11459. }
  11460. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  11461. if( namedArgs[n].ctx )
  11462. {
  11463. asDELETE(namedArgs[n].ctx, asCExprContext);
  11464. }
  11465. if( !isOK )
  11466. return -1;
  11467. }
  11468. return 0;
  11469. }
  11470. int asCCompiler::GetPrecedence(asCScriptNode *op)
  11471. {
  11472. // x ** y
  11473. // x * y, x / y, x % y
  11474. // x + y, x - y
  11475. // x <= y, x < y, x >= y, x > y
  11476. // x = =y, x != y, x xor y, x is y, x !is y
  11477. // x and y
  11478. // x or y
  11479. // The following are not used in this function,
  11480. // but should have lower precedence than the above
  11481. // x ? y : z
  11482. // x = y
  11483. // The expression term have the highest precedence
  11484. if( op->nodeType == snExprTerm )
  11485. return 1;
  11486. // Evaluate operators by token
  11487. int tokenType = op->tokenType;
  11488. if( tokenType == ttStarStar )
  11489. return 0;
  11490. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  11491. return -1;
  11492. if( tokenType == ttPlus || tokenType == ttMinus )
  11493. return -2;
  11494. if( tokenType == ttBitShiftLeft ||
  11495. tokenType == ttBitShiftRight ||
  11496. tokenType == ttBitShiftRightArith )
  11497. return -3;
  11498. if( tokenType == ttAmp )
  11499. return -4;
  11500. if( tokenType == ttBitXor )
  11501. return -5;
  11502. if( tokenType == ttBitOr )
  11503. return -6;
  11504. if( tokenType == ttLessThanOrEqual ||
  11505. tokenType == ttLessThan ||
  11506. tokenType == ttGreaterThanOrEqual ||
  11507. tokenType == ttGreaterThan )
  11508. return -7;
  11509. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  11510. return -8;
  11511. if( tokenType == ttAnd )
  11512. return -9;
  11513. if( tokenType == ttOr )
  11514. return -10;
  11515. // Unknown operator
  11516. asASSERT(false);
  11517. return 0;
  11518. }
  11519. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11520. {
  11521. matches.SetLength(0);
  11522. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  11523. {
  11524. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  11525. // Does the function have arguments enough?
  11526. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  11527. continue;
  11528. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  11529. if( cost != -1 )
  11530. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  11531. }
  11532. return (asUINT)matches.GetLength();
  11533. }
  11534. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11535. {
  11536. // void expressions can match any out parameter, but nothing else
  11537. if( argExpr->IsVoidExpression() )
  11538. {
  11539. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  11540. return 0;
  11541. return -1;
  11542. }
  11543. // Anonymous init lists can only match parameters that can be initialized with a list
  11544. if (argExpr->IsAnonymousInitList())
  11545. {
  11546. if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) ||
  11547. desc->parameterTypes[paramNum].GetBehaviour() == 0 ||
  11548. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 )
  11549. {
  11550. return -1;
  11551. }
  11552. return 0;
  11553. }
  11554. // Can we make the match by implicit conversion?
  11555. asCExprContext ti(engine);
  11556. ti.type = argExpr->type;
  11557. ti.methodName = argExpr->methodName;
  11558. ti.enumValue = argExpr->enumValue;
  11559. ti.exprNode = argExpr->exprNode;
  11560. if( argExpr->type.dataType.IsPrimitive() )
  11561. ti.type.dataType.MakeReference(false);
  11562. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  11563. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  11564. allowObjectConstruct = false;
  11565. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  11566. // If the function parameter is an inout-reference then it must not be possible to call the
  11567. // function with an incorrect argument type, even though the type can normally be converted.
  11568. if( desc->parameterTypes[paramNum].IsReference() &&
  11569. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  11570. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  11571. {
  11572. // Observe, that the below checks are only necessary for when unsafe references have been
  11573. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  11574. // for these value types.
  11575. // Don't allow a primitive to be converted to a reference of another primitive type
  11576. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  11577. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  11578. {
  11579. asASSERT( engine->ep.allowUnsafeReferences );
  11580. return -1;
  11581. }
  11582. // Don't allow an enum to be converted to a reference of another enum type
  11583. if( desc->parameterTypes[paramNum].IsEnumType() &&
  11584. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  11585. {
  11586. asASSERT( engine->ep.allowUnsafeReferences );
  11587. return -1;
  11588. }
  11589. // Don't allow a non-handle expression to be converted to a reference to a handle
  11590. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  11591. !argExpr->type.dataType.IsObjectHandle() )
  11592. {
  11593. asASSERT( engine->ep.allowUnsafeReferences );
  11594. return -1;
  11595. }
  11596. // Don't allow a value type to be converted
  11597. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  11598. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  11599. {
  11600. asASSERT( engine->ep.allowUnsafeReferences );
  11601. return -1;
  11602. }
  11603. }
  11604. // How well does the argument match the function parameter?
  11605. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  11606. return cost;
  11607. // No match is available
  11608. return -1;
  11609. }
  11610. int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  11611. {
  11612. // Reference parameters whose value won't be used don't evaluate the expression
  11613. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  11614. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  11615. {
  11616. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  11617. asCExprContext *orig = asNEW(asCExprContext)(engine);
  11618. if( orig == 0 )
  11619. {
  11620. // Out of memory
  11621. return -1;
  11622. }
  11623. MergeExprBytecodeAndType(orig, arg);
  11624. arg->origExpr = orig;
  11625. }
  11626. int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  11627. if (r < 0)
  11628. return r;
  11629. // arg still holds the original expression for output parameters
  11630. ctx->bc.AddCode(&arg->bc);
  11631. return 0;
  11632. }
  11633. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  11634. {
  11635. DetermineSingleFunc(lctx, node);
  11636. DetermineSingleFunc(rctx, node);
  11637. ctx->exprNode = node;
  11638. // What type of operator is it?
  11639. if( token == ttUnrecognizedToken )
  11640. token = node->tokenType;
  11641. if( token == ttUnrecognizedToken )
  11642. {
  11643. // This happens when the compiler is inferring an assignment
  11644. // operation from another action, for example in preparing a value
  11645. // as a function argument
  11646. token = ttAssignment;
  11647. }
  11648. // boolean operators are not overloadable
  11649. if( token == ttAnd ||
  11650. token == ttOr ||
  11651. token == ttXor )
  11652. return false;
  11653. // Dual operators can also be implemented as class methods
  11654. if( token == ttEqual ||
  11655. token == ttNotEqual )
  11656. {
  11657. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11658. // Find the matching opEquals method
  11659. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11660. if( r == 0 )
  11661. {
  11662. // Try again by switching the order of the operands
  11663. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11664. }
  11665. if( r == 1 )
  11666. {
  11667. if( token == ttNotEqual )
  11668. ctx->bc.InstrSHORT(asBC_NOT, (short)ctx->type.stackOffset);
  11669. // Success, don't continue
  11670. return true;
  11671. }
  11672. else if( r < 0 )
  11673. {
  11674. // Compiler error, don't continue
  11675. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11676. return true;
  11677. }
  11678. }
  11679. if( token == ttEqual ||
  11680. token == ttNotEqual ||
  11681. token == ttLessThan ||
  11682. token == ttLessThanOrEqual ||
  11683. token == ttGreaterThan ||
  11684. token == ttGreaterThanOrEqual )
  11685. {
  11686. bool swappedOrder = false;
  11687. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11688. // Find the matching opCmp method
  11689. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11690. if( r == 0 )
  11691. {
  11692. // Try again by switching the order of the operands
  11693. swappedOrder = true;
  11694. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11695. }
  11696. if( r == 1 )
  11697. {
  11698. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11699. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11700. ctx->bc.InstrW_DW(asBC_CMPIi, (short)ctx->type.stackOffset, 0);
  11701. if( token == ttEqual )
  11702. ctx->bc.Instr(asBC_TZ);
  11703. else if( token == ttNotEqual )
  11704. ctx->bc.Instr(asBC_TNZ);
  11705. else if( (token == ttLessThan && !swappedOrder) ||
  11706. (token == ttGreaterThan && swappedOrder) )
  11707. ctx->bc.Instr(asBC_TS);
  11708. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  11709. (token == ttGreaterThanOrEqual && swappedOrder) )
  11710. ctx->bc.Instr(asBC_TNP);
  11711. else if( (token == ttGreaterThan && !swappedOrder) ||
  11712. (token == ttLessThan && swappedOrder) )
  11713. ctx->bc.Instr(asBC_TP);
  11714. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  11715. (token == ttLessThanOrEqual && swappedOrder) )
  11716. ctx->bc.Instr(asBC_TNS);
  11717. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11718. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  11719. // Success, don't continue
  11720. return true;
  11721. }
  11722. else if( r < 0 )
  11723. {
  11724. // Compiler error, don't continue
  11725. #if AS_SIZEOF_BOOL == 1
  11726. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11727. #else
  11728. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11729. #endif
  11730. return true;
  11731. }
  11732. }
  11733. // The rest of the operators are not commutative, and doesn't require specific return type
  11734. const char *op = 0, *op_r = 0;
  11735. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11736. {
  11737. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  11738. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  11739. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  11740. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  11741. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  11742. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  11743. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  11744. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  11745. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  11746. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  11747. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  11748. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  11749. }
  11750. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  11751. if( op && op_r )
  11752. {
  11753. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11754. // Find the matching operator method
  11755. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  11756. if( r == 0 )
  11757. {
  11758. // Try again by switching the order of the operands, and using the reversed operator
  11759. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  11760. }
  11761. if( r == 1 )
  11762. {
  11763. // Success, don't continue
  11764. return true;
  11765. }
  11766. else if( r < 0 )
  11767. {
  11768. // Compiler error, don't continue
  11769. ctx->type.SetDummy();
  11770. return true;
  11771. }
  11772. }
  11773. // Assignment operators
  11774. op = 0;
  11775. if( isHandle )
  11776. {
  11777. // Only asOBJ_ASHANDLE types can get here
  11778. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  11779. asASSERT( token == ttAssignment );
  11780. if( token == ttAssignment )
  11781. op = "opHndlAssign";
  11782. }
  11783. else
  11784. {
  11785. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11786. {
  11787. case ttAssignment: op = "opAssign"; break;
  11788. case ttAddAssign: op = "opAddAssign"; break;
  11789. case ttSubAssign: op = "opSubAssign"; break;
  11790. case ttMulAssign: op = "opMulAssign"; break;
  11791. case ttDivAssign: op = "opDivAssign"; break;
  11792. case ttModAssign: op = "opModAssign"; break;
  11793. case ttPowAssign: op = "opPowAssign"; break;
  11794. case ttOrAssign: op = "opOrAssign"; break;
  11795. case ttAndAssign: op = "opAndAssign"; break;
  11796. case ttXorAssign: op = "opXorAssign"; break;
  11797. case ttShiftLeftAssign: op = "opShlAssign"; break;
  11798. case ttShiftRightLAssign: op = "opShrAssign"; break;
  11799. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  11800. }
  11801. }
  11802. if( op )
  11803. {
  11804. if( builder->engine->ep.disallowValueAssignForRefType &&
  11805. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  11806. {
  11807. if( token == ttAssignment )
  11808. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  11809. else
  11810. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  11811. // Set a dummy output
  11812. ctx->type.Set(lctx->type.dataType);
  11813. return true;
  11814. }
  11815. // TODO: Shouldn't accept const lvalue with the assignment operators
  11816. // Find the matching operator method
  11817. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  11818. if( r == 1 )
  11819. {
  11820. // Success, don't continue
  11821. return true;
  11822. }
  11823. else if( r < 0 )
  11824. {
  11825. // Compiler error, don't continue
  11826. ctx->type.SetDummy();
  11827. return true;
  11828. }
  11829. }
  11830. // No suitable operator was found
  11831. return false;
  11832. }
  11833. // Returns negative on compile error
  11834. // zero on no matching operator
  11835. // one on matching operator
  11836. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  11837. {
  11838. // Find the matching method
  11839. if( lctx->type.dataType.IsObject() &&
  11840. (!lctx->type.isExplicitHandle ||
  11841. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) &&
  11842. !lctx->type.IsNullConstant() )
  11843. {
  11844. asUINT n;
  11845. // Is the left value a const?
  11846. bool isConst = lctx->type.dataType.IsObjectConst();
  11847. asCArray<int> funcs;
  11848. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  11849. asASSERT(ot);
  11850. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  11851. {
  11852. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11853. asASSERT( func );
  11854. if( func && func->name == methodName &&
  11855. (!specificReturn || func->returnType == returnType) &&
  11856. func->parameterTypes.GetLength() == 1 &&
  11857. (!isConst || func->IsReadOnly()) )
  11858. {
  11859. // Make sure the method is accessible by the module
  11860. if( builder->module->m_accessMask & func->accessMask )
  11861. {
  11862. funcs.PushLast(func->id);
  11863. }
  11864. }
  11865. }
  11866. // Which is the best matching function?
  11867. asCArray<asSOverloadCandidate> tempFuncs;
  11868. MatchArgument(funcs, tempFuncs, rctx, 0);
  11869. // Find the lowest cost operator(s)
  11870. asCArray<int> ops;
  11871. asUINT bestCost = asUINT(-1);
  11872. for( n = 0; n < tempFuncs.GetLength(); ++n )
  11873. {
  11874. asUINT cost = tempFuncs[n].cost;
  11875. if( cost < bestCost )
  11876. {
  11877. ops.SetLength(0);
  11878. bestCost = cost;
  11879. }
  11880. if( cost == bestCost )
  11881. ops.PushLast(tempFuncs[n].funcId);
  11882. }
  11883. // If the object is not const, then we need to prioritize non-const methods
  11884. if( !isConst )
  11885. FilterConst(ops);
  11886. // Did we find an operator?
  11887. if( ops.GetLength() == 1 )
  11888. {
  11889. // Reserve the variables used in the right expression so the new temporary
  11890. // variable allocated for the left operand isn't accidentally overwritten.
  11891. int l = int(reservedVariables.GetLength());
  11892. rctx->bc.GetVarsUsed(reservedVariables);
  11893. // Process the lctx expression as get accessor
  11894. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  11895. return -1;
  11896. reservedVariables.SetLength(l);
  11897. asCExprContext tmpCtx(engine);
  11898. if (leftToRight)
  11899. {
  11900. // Make sure lctx is in fact a variable. If it is a reference there is no
  11901. // guarantee that the reference will stay alive throughout the evaluation of rctx
  11902. if (!lctx->type.isVariable)
  11903. {
  11904. // Reserve the variables used in the right expression so the new temporary
  11905. // variable allocated for the left operand isn't accidentally overwritten.
  11906. l = int(reservedVariables.GetLength());
  11907. rctx->bc.GetVarsUsed(reservedVariables);
  11908. if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
  11909. {
  11910. // If the application allows unsafe references, then it is not necessary to
  11911. // make a copy of the object, just store the reference as a local variable
  11912. // Allocate a temporary variable as reference to the type
  11913. asCDataType dt = lctx->type.dataType;
  11914. dt.MakeReference(true);
  11915. int offset = AllocateVariable(dt, true, false, true);
  11916. Dereference(lctx, true);
  11917. // Copy the pointer to the temporary variable
  11918. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11919. if (lctx->type.dataType.IsFuncdef())
  11920. lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11921. else
  11922. lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo());
  11923. lctx->type.SetVariable(dt, offset, true);
  11924. }
  11925. else
  11926. {
  11927. if (lctx->type.dataType.SupportHandles())
  11928. lctx->type.dataType.MakeHandle(true);
  11929. PrepareTemporaryVariable(node, lctx);
  11930. }
  11931. reservedVariables.SetLength(l);
  11932. }
  11933. // Move the bytecode for the left operand to a temporary context
  11934. // so we can later make sure this is computed first
  11935. tmpCtx.bc.AddCode(&lctx->bc);
  11936. tmpCtx.bc.Instr(asBC_PopPtr);
  11937. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  11938. // This will be placed after rctx by MakeFunctionCall below
  11939. lctx->bc.InstrWORD(asBC_PSF, (short)lctx->type.stackOffset);
  11940. // Implicitly dereference handle parameters sent by reference
  11941. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  11942. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  11943. lctx->bc.Instr(asBC_RDSPtr);
  11944. }
  11945. else
  11946. {
  11947. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  11948. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  11949. asCArray<int> usedVars;
  11950. lctx->bc.GetVarsUsed(usedVars);
  11951. asUINT oldReservedVars = reservedVariables.GetLength();
  11952. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  11953. {
  11954. if (rctx->deferredParams[n].argType.isTemporary &&
  11955. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  11956. {
  11957. if (reservedVariables.GetLength() == oldReservedVars)
  11958. reservedVariables.Concatenate(usedVars);
  11959. // Allocate a new variable for the deferred argument
  11960. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  11961. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  11962. rctx->deferredParams[n].argType.stackOffset = short(offset);
  11963. rctx->bc.ExchangeVar(oldVar, offset);
  11964. ReleaseTemporaryVariable(oldVar, 0);
  11965. }
  11966. }
  11967. reservedVariables.SetLength(oldReservedVars);
  11968. }
  11969. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  11970. asCArray<asCExprContext *> args;
  11971. args.PushLast(rctx);
  11972. MergeExprBytecode(ctx, lctx);
  11973. ctx->type = lctx->type;
  11974. if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 )
  11975. return -1;
  11976. // Rearrange the bytecode so the left argument is computed first
  11977. if (leftToRight)
  11978. {
  11979. tmpCtx.bc.AddCode(&ctx->bc);
  11980. ctx->bc.AddCode(&tmpCtx.bc);
  11981. }
  11982. // Found matching operator
  11983. return 1;
  11984. }
  11985. else if( ops.GetLength() > 1 )
  11986. {
  11987. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11988. PrintMatchingFuncs(ops, node);
  11989. ctx->type.SetDummy();
  11990. // Compiler error
  11991. return -1;
  11992. }
  11993. }
  11994. // No matching operator
  11995. return 0;
  11996. }
  11997. int asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  11998. {
  11999. if( objectType )
  12000. Dereference(ctx, true);
  12001. // Store the expression node for error reporting
  12002. if( ctx->exprNode == 0 )
  12003. ctx->exprNode = node;
  12004. asCByteCode objBC(engine);
  12005. objBC.AddCode(&ctx->bc);
  12006. int r = PrepareFunctionCall(funcId, &ctx->bc, args);
  12007. if (r < 0)
  12008. return r;
  12009. // Verify if any of the args variable offsets are used in the other code.
  12010. // If they are exchange the offset for a new one
  12011. asUINT n;
  12012. for( n = 0; n < args.GetLength(); n++ )
  12013. {
  12014. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  12015. {
  12016. // Release the current temporary variable
  12017. ReleaseTemporaryVariable(args[n]->type, 0);
  12018. asCDataType dt = args[n]->type.dataType;
  12019. dt.MakeReference(false);
  12020. int l = int(reservedVariables.GetLength());
  12021. objBC.GetVarsUsed(reservedVariables);
  12022. ctx->bc.GetVarsUsed(reservedVariables);
  12023. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  12024. reservedVariables.SetLength(l);
  12025. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  12026. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  12027. args[n]->type.stackOffset = (short)newOffset;
  12028. args[n]->type.isTemporary = true;
  12029. args[n]->type.isVariable = true;
  12030. }
  12031. }
  12032. // If the function will return a value type on the stack, then we must allocate space
  12033. // for that here and push the address on the stack as a hidden argument to the function
  12034. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  12035. if( func->DoesReturnOnStack() )
  12036. {
  12037. asASSERT(!useVariable);
  12038. useVariable = true;
  12039. stackOffset = AllocateVariable(func->returnType, true);
  12040. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  12041. }
  12042. ctx->bc.AddCode(&objBC);
  12043. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  12044. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  12045. return 0;
  12046. }
  12047. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  12048. {
  12049. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  12050. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  12051. {
  12052. Error(TXT_INVALID_OP_ON_METHOD, node);
  12053. return -1;
  12054. }
  12055. // Don't allow any operators on void expressions
  12056. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  12057. {
  12058. Error(TXT_VOID_CANT_BE_OPERAND, node);
  12059. return -1;
  12060. }
  12061. if( op == ttUnrecognizedToken )
  12062. op = node->tokenType;
  12063. IsVariableInitialized(&lctx->type, node);
  12064. IsVariableInitialized(&rctx->type, node);
  12065. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  12066. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  12067. op == ttIs || op == ttNotIs )
  12068. {
  12069. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  12070. return 0;
  12071. }
  12072. else
  12073. {
  12074. // Compile an overloaded operator for the two operands
  12075. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  12076. return 0;
  12077. // If both operands are objects, then we shouldn't continue
  12078. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  12079. {
  12080. asCString str;
  12081. 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());
  12082. Error(str, node);
  12083. ctx->type.SetDummy();
  12084. return -1;
  12085. }
  12086. // Process the property get accessors (if any)
  12087. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  12088. return -1;
  12089. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  12090. return -1;
  12091. // Make sure we have two variables or constants
  12092. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  12093. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  12094. // Make sure lctx doesn't end up with a variable used in rctx
  12095. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  12096. {
  12097. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  12098. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  12099. ReleaseTemporaryVariable(offset, 0);
  12100. }
  12101. // Math operators
  12102. // + - * / % ** += -= *= /= %= **=
  12103. if( op == ttPlus || op == ttAddAssign ||
  12104. op == ttMinus || op == ttSubAssign ||
  12105. op == ttStar || op == ttMulAssign ||
  12106. op == ttSlash || op == ttDivAssign ||
  12107. op == ttPercent || op == ttModAssign ||
  12108. op == ttStarStar || op == ttPowAssign )
  12109. {
  12110. CompileMathOperator(node, lctx, rctx, ctx, op);
  12111. return 0;
  12112. }
  12113. // Bitwise operators
  12114. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  12115. if( op == ttAmp || op == ttAndAssign ||
  12116. op == ttBitOr || op == ttOrAssign ||
  12117. op == ttBitXor || op == ttXorAssign ||
  12118. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12119. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12120. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12121. {
  12122. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  12123. return 0;
  12124. }
  12125. // Comparison operators
  12126. // == != < > <= >=
  12127. if( op == ttEqual || op == ttNotEqual ||
  12128. op == ttLessThan || op == ttLessThanOrEqual ||
  12129. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  12130. {
  12131. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  12132. return 0;
  12133. }
  12134. // Boolean operators
  12135. // && || ^^
  12136. if( op == ttAnd || op == ttOr || op == ttXor )
  12137. {
  12138. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  12139. return 0;
  12140. }
  12141. }
  12142. asASSERT(false);
  12143. return -1;
  12144. }
  12145. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12146. {
  12147. int l = int(reservedVariables.GetLength());
  12148. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12149. ConvertToTempVariable(ctx);
  12150. reservedVariables.SetLength(l);
  12151. }
  12152. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  12153. {
  12154. // This is only used for primitive types and null handles
  12155. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  12156. ConvertToVariable(ctx);
  12157. if( !ctx->type.isTemporary )
  12158. {
  12159. if( ctx->type.dataType.IsPrimitive() )
  12160. {
  12161. // Copy the variable to a temporary variable
  12162. int offset = AllocateVariable(ctx->type.dataType, true);
  12163. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12164. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  12165. else
  12166. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  12167. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12168. }
  12169. else
  12170. {
  12171. // We should never get here
  12172. asASSERT(false);
  12173. }
  12174. }
  12175. }
  12176. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  12177. {
  12178. // We should never get here while the context is still an unprocessed property accessor
  12179. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  12180. int offset;
  12181. if( !ctx->type.isVariable &&
  12182. (ctx->type.dataType.IsObjectHandle() ||
  12183. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  12184. {
  12185. offset = AllocateVariable(ctx->type.dataType, true);
  12186. if( ctx->type.IsNullConstant() )
  12187. {
  12188. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  12189. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  12190. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  12191. }
  12192. else
  12193. {
  12194. Dereference(ctx, true);
  12195. // Copy the object handle to a variable
  12196. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12197. if( ctx->type.dataType.IsFuncdef() )
  12198. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  12199. else
  12200. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  12201. ctx->bc.Instr(asBC_PopPtr);
  12202. }
  12203. // As this is an object the reference must be placed on the stack
  12204. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12205. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12206. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12207. ctx->type.dataType.MakeHandle(true);
  12208. ctx->type.dataType.MakeReference(true);
  12209. }
  12210. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  12211. ctx->type.dataType.IsPrimitive() )
  12212. {
  12213. if( ctx->type.isConstant )
  12214. {
  12215. offset = AllocateVariable(ctx->type.dataType, true);
  12216. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12217. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  12218. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12219. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  12220. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  12221. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  12222. else
  12223. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  12224. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12225. return;
  12226. }
  12227. else
  12228. {
  12229. asASSERT(ctx->type.dataType.IsPrimitive());
  12230. asASSERT(ctx->type.dataType.IsReference());
  12231. ctx->type.dataType.MakeReference(false);
  12232. offset = AllocateVariable(ctx->type.dataType, true);
  12233. // Read the value from the address in the register directly into the variable
  12234. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12235. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  12236. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12237. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  12238. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12239. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  12240. else
  12241. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  12242. }
  12243. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12244. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12245. }
  12246. }
  12247. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12248. {
  12249. int l = int(reservedVariables.GetLength());
  12250. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12251. ConvertToVariable(ctx);
  12252. reservedVariables.SetLength(l);
  12253. }
  12254. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  12255. {
  12256. asCArray<int> funcs;
  12257. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  12258. if( ot )
  12259. {
  12260. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  12261. {
  12262. // Consider only implicit casts
  12263. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  12264. if( func->name == "opImplConv" &&
  12265. func->returnType.IsPrimitive() &&
  12266. func->parameterTypes.GetLength() == 0 )
  12267. funcs.PushLast(ot->methods[n]);
  12268. }
  12269. // Use the one with the highest precision
  12270. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  12271. while( funcs.GetLength() > 1 )
  12272. {
  12273. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  12274. int value1 = 11, value2 = 11;
  12275. for( asUINT i = 0; i < 10; i++ )
  12276. {
  12277. if( returnType == match[i] )
  12278. {
  12279. value1 = i;
  12280. break;
  12281. }
  12282. }
  12283. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  12284. {
  12285. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  12286. for( asUINT i = 0; i < 10; i++ )
  12287. {
  12288. if( returnType == match[i] )
  12289. {
  12290. value2 = i;
  12291. break;
  12292. }
  12293. }
  12294. if( value2 >= value1 )
  12295. {
  12296. // Remove this and continue searching
  12297. funcs.RemoveIndexUnordered(n--);
  12298. }
  12299. else
  12300. {
  12301. // Remove the first, and start over
  12302. funcs.RemoveIndexUnordered(0);
  12303. break;
  12304. }
  12305. }
  12306. }
  12307. // Do the conversion
  12308. if( funcs.GetLength() )
  12309. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  12310. }
  12311. }
  12312. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12313. {
  12314. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12315. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  12316. // If either operand is a non-primitive then use the primitive type
  12317. if( !lctx->type.dataType.IsPrimitive() )
  12318. {
  12319. int l = int(reservedVariables.GetLength());
  12320. rctx->bc.GetVarsUsed(reservedVariables);
  12321. ImplicitConvObjectToBestMathType(lctx, node);
  12322. reservedVariables.SetLength(l);
  12323. }
  12324. if( !rctx->type.dataType.IsPrimitive() )
  12325. {
  12326. int l = int(reservedVariables.GetLength());
  12327. lctx->bc.GetVarsUsed(reservedVariables);
  12328. ImplicitConvObjectToBestMathType(rctx, node);
  12329. reservedVariables.SetLength(l);
  12330. }
  12331. // Both types must now be primitives. Implicitly convert them so they match
  12332. asCDataType to;
  12333. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12334. to.SetTokenType(ttDouble);
  12335. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12336. to.SetTokenType(ttFloat);
  12337. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12338. {
  12339. // Convert to int64 if both are signed or if one is non-constant and signed
  12340. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12341. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12342. to.SetTokenType(ttInt64);
  12343. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12344. to.SetTokenType(ttUInt64);
  12345. else
  12346. to.SetTokenType(ttInt64);
  12347. }
  12348. else
  12349. {
  12350. // Convert to int32 if both are signed or if one is non-constant and signed
  12351. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12352. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12353. to.SetTokenType(ttInt);
  12354. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12355. to.SetTokenType(ttUInt);
  12356. else
  12357. to.SetTokenType(ttInt);
  12358. }
  12359. // If doing an operation with double constant and float variable, the constant should be converted to float
  12360. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12361. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12362. to.SetTokenType(ttFloat);
  12363. if( op == ttUnrecognizedToken )
  12364. op = node->tokenType;
  12365. // If integer division is disabled, convert to floating-point
  12366. if( engine->ep.disableIntegerDivision &&
  12367. (op == ttSlash || op == ttDivAssign) &&
  12368. (to.IsIntegerType() || to.IsUnsignedType()) )
  12369. {
  12370. // Use double to avoid losing precision when dividing with 32bit ints
  12371. // For 64bit ints there is unfortunately no greater type so with those
  12372. // there is still a risk of loosing precision
  12373. to.SetTokenType(ttDouble);
  12374. }
  12375. // Do the actual conversion
  12376. int l = int(reservedVariables.GetLength());
  12377. rctx->bc.GetVarsUsed(reservedVariables);
  12378. lctx->bc.GetVarsUsed(reservedVariables);
  12379. if( lctx->type.dataType.IsReference() )
  12380. ConvertToVariable(lctx);
  12381. if( rctx->type.dataType.IsReference() )
  12382. ConvertToVariable(rctx);
  12383. if( to.IsPrimitive() )
  12384. {
  12385. // ttStarStar allows an integer, right-hand operand and a double
  12386. // left-hand operand.
  12387. if( (op == ttStarStar || op == ttPowAssign) &&
  12388. lctx->type.dataType.IsDoubleType() &&
  12389. (rctx->type.dataType.IsIntegerType() ||
  12390. rctx->type.dataType.IsUnsignedType()) )
  12391. {
  12392. to.SetTokenType(ttInt);
  12393. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12394. to.SetTokenType(ttDouble);
  12395. }
  12396. else
  12397. {
  12398. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12399. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12400. }
  12401. }
  12402. reservedVariables.SetLength(l);
  12403. // Verify that the conversion was successful
  12404. if( !lctx->type.dataType.IsIntegerType() &&
  12405. !lctx->type.dataType.IsUnsignedType() &&
  12406. !lctx->type.dataType.IsFloatType() &&
  12407. !lctx->type.dataType.IsDoubleType() )
  12408. {
  12409. asCString str;
  12410. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12411. Error(str, node);
  12412. ctx->type.SetDummy();
  12413. return;
  12414. }
  12415. if( !rctx->type.dataType.IsIntegerType() &&
  12416. !rctx->type.dataType.IsUnsignedType() &&
  12417. !rctx->type.dataType.IsFloatType() &&
  12418. !rctx->type.dataType.IsDoubleType() )
  12419. {
  12420. asCString str;
  12421. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12422. Error(str, node);
  12423. ctx->type.SetDummy();
  12424. return;
  12425. }
  12426. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12427. // Verify if we are dividing with a constant zero
  12428. if( rctx->type.isConstant &&
  12429. (op == ttSlash || op == ttDivAssign ||
  12430. op == ttPercent || op == ttModAssign) &&
  12431. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  12432. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  12433. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  12434. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  12435. {
  12436. Error(TXT_DIVIDE_BY_ZERO, node);
  12437. }
  12438. if( !isConstant )
  12439. {
  12440. ConvertToVariableNotIn(lctx, rctx);
  12441. ConvertToVariableNotIn(rctx, lctx);
  12442. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12443. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12444. if( op == ttAddAssign || op == ttSubAssign ||
  12445. op == ttMulAssign || op == ttDivAssign ||
  12446. op == ttModAssign || op == ttPowAssign )
  12447. {
  12448. // Merge the operands in the different order so that they are evaluated correctly
  12449. MergeExprBytecode(ctx, rctx);
  12450. MergeExprBytecode(ctx, lctx);
  12451. // We must not process the deferred parameters yet, as
  12452. // it may overwrite the lvalue kept in the register
  12453. }
  12454. else
  12455. {
  12456. MergeExprBytecode(ctx, lctx);
  12457. MergeExprBytecode(ctx, rctx);
  12458. ProcessDeferredParams(ctx);
  12459. }
  12460. asEBCInstr instruction = asBC_ADDi;
  12461. if( lctx->type.dataType.IsIntegerType() ||
  12462. lctx->type.dataType.IsUnsignedType() )
  12463. {
  12464. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12465. {
  12466. if( op == ttPlus || op == ttAddAssign )
  12467. instruction = asBC_ADDi;
  12468. else if( op == ttMinus || op == ttSubAssign )
  12469. instruction = asBC_SUBi;
  12470. else if( op == ttStar || op == ttMulAssign )
  12471. instruction = asBC_MULi;
  12472. else if( op == ttSlash || op == ttDivAssign )
  12473. {
  12474. if( lctx->type.dataType.IsIntegerType() )
  12475. instruction = asBC_DIVi;
  12476. else
  12477. instruction = asBC_DIVu;
  12478. }
  12479. else if( op == ttPercent || op == ttModAssign )
  12480. {
  12481. if( lctx->type.dataType.IsIntegerType() )
  12482. instruction = asBC_MODi;
  12483. else
  12484. instruction = asBC_MODu;
  12485. }
  12486. else if( op == ttStarStar || op == ttPowAssign )
  12487. {
  12488. if( lctx->type.dataType.IsIntegerType() )
  12489. instruction = asBC_POWi;
  12490. else
  12491. instruction = asBC_POWu;
  12492. }
  12493. }
  12494. else
  12495. {
  12496. if( op == ttPlus || op == ttAddAssign )
  12497. instruction = asBC_ADDi64;
  12498. else if( op == ttMinus || op == ttSubAssign )
  12499. instruction = asBC_SUBi64;
  12500. else if( op == ttStar || op == ttMulAssign )
  12501. instruction = asBC_MULi64;
  12502. else if( op == ttSlash || op == ttDivAssign )
  12503. {
  12504. if( lctx->type.dataType.IsIntegerType() )
  12505. instruction = asBC_DIVi64;
  12506. else
  12507. instruction = asBC_DIVu64;
  12508. }
  12509. else if( op == ttPercent || op == ttModAssign )
  12510. {
  12511. if( lctx->type.dataType.IsIntegerType() )
  12512. instruction = asBC_MODi64;
  12513. else
  12514. instruction = asBC_MODu64;
  12515. }
  12516. else if( op == ttStarStar || op == ttPowAssign )
  12517. {
  12518. if( lctx->type.dataType.IsIntegerType() )
  12519. instruction = asBC_POWi64;
  12520. else
  12521. instruction = asBC_POWu64;
  12522. }
  12523. }
  12524. }
  12525. else if( lctx->type.dataType.IsFloatType() )
  12526. {
  12527. if( op == ttPlus || op == ttAddAssign )
  12528. instruction = asBC_ADDf;
  12529. else if( op == ttMinus || op == ttSubAssign )
  12530. instruction = asBC_SUBf;
  12531. else if( op == ttStar || op == ttMulAssign )
  12532. instruction = asBC_MULf;
  12533. else if( op == ttSlash || op == ttDivAssign )
  12534. instruction = asBC_DIVf;
  12535. else if( op == ttPercent || op == ttModAssign )
  12536. instruction = asBC_MODf;
  12537. else if( op == ttStarStar || op == ttPowAssign )
  12538. instruction = asBC_POWf;
  12539. }
  12540. else if( lctx->type.dataType.IsDoubleType() )
  12541. {
  12542. if( rctx->type.dataType.IsIntegerType() )
  12543. {
  12544. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12545. if( op == ttStarStar || op == ttPowAssign )
  12546. instruction = asBC_POWdi;
  12547. else
  12548. asASSERT(false); // Should not be possible
  12549. }
  12550. else
  12551. {
  12552. if( op == ttPlus || op == ttAddAssign )
  12553. instruction = asBC_ADDd;
  12554. else if( op == ttMinus || op == ttSubAssign )
  12555. instruction = asBC_SUBd;
  12556. else if( op == ttStar || op == ttMulAssign )
  12557. instruction = asBC_MULd;
  12558. else if( op == ttSlash || op == ttDivAssign )
  12559. instruction = asBC_DIVd;
  12560. else if( op == ttPercent || op == ttModAssign )
  12561. instruction = asBC_MODd;
  12562. else if( op == ttStarStar || op == ttPowAssign )
  12563. instruction = asBC_POWd;
  12564. }
  12565. }
  12566. else
  12567. {
  12568. // Shouldn't be possible
  12569. asASSERT(false);
  12570. }
  12571. // Do the operation
  12572. int a = AllocateVariable(lctx->type.dataType, true);
  12573. int b = lctx->type.stackOffset;
  12574. int c = rctx->type.stackOffset;
  12575. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12576. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12577. }
  12578. else
  12579. {
  12580. // Both values are constants
  12581. if( lctx->type.dataType.IsIntegerType() ||
  12582. lctx->type.dataType.IsUnsignedType() )
  12583. {
  12584. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12585. {
  12586. int v = 0;
  12587. if( op == ttPlus )
  12588. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  12589. else if( op == ttMinus )
  12590. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12591. else if( op == ttStar )
  12592. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  12593. else if( op == ttSlash )
  12594. {
  12595. // TODO: Should probably report an error, rather than silently convert the value to 0
  12596. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12597. v = 0;
  12598. else
  12599. if( lctx->type.dataType.IsIntegerType() )
  12600. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  12601. else
  12602. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  12603. }
  12604. else if( op == ttPercent )
  12605. {
  12606. // TODO: Should probably report an error, rather than silently convert the value to 0
  12607. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12608. v = 0;
  12609. else
  12610. if( lctx->type.dataType.IsIntegerType() )
  12611. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  12612. else
  12613. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  12614. }
  12615. else if( op == ttStarStar )
  12616. {
  12617. bool isOverflow;
  12618. if( lctx->type.dataType.IsIntegerType() )
  12619. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  12620. else
  12621. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  12622. if( isOverflow )
  12623. Error(TXT_POW_OVERFLOW, node);
  12624. }
  12625. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12626. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12627. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  12628. ctx->type.dataType.SetTokenType(ttInt);
  12629. }
  12630. else
  12631. {
  12632. asQWORD v = 0;
  12633. if( op == ttPlus )
  12634. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  12635. else if( op == ttMinus )
  12636. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12637. else if( op == ttStar )
  12638. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  12639. else if( op == ttSlash )
  12640. {
  12641. // TODO: Should probably report an error, rather than silently convert the value to 0
  12642. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12643. v = 0;
  12644. else
  12645. if( lctx->type.dataType.IsIntegerType() )
  12646. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  12647. else
  12648. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  12649. }
  12650. else if( op == ttPercent )
  12651. {
  12652. // TODO: Should probably report an error, rather than silently convert the value to 0
  12653. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12654. v = 0;
  12655. else
  12656. if( lctx->type.dataType.IsIntegerType() )
  12657. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  12658. else
  12659. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  12660. }
  12661. else if( op == ttStarStar )
  12662. {
  12663. bool isOverflow;
  12664. if( lctx->type.dataType.IsIntegerType() )
  12665. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  12666. else
  12667. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  12668. if( isOverflow )
  12669. Error(TXT_POW_OVERFLOW, node);
  12670. }
  12671. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12672. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12673. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  12674. ctx->type.dataType.SetTokenType(ttInt64);
  12675. }
  12676. }
  12677. else if( lctx->type.dataType.IsFloatType() )
  12678. {
  12679. float v = 0.0f;
  12680. if( op == ttPlus )
  12681. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  12682. else if( op == ttMinus )
  12683. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12684. else if( op == ttStar )
  12685. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  12686. else if( op == ttSlash )
  12687. {
  12688. if( rctx->type.GetConstantF() == 0 )
  12689. v = 0;
  12690. else
  12691. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  12692. }
  12693. else if( op == ttPercent )
  12694. {
  12695. if( rctx->type.GetConstantF() == 0 )
  12696. v = 0;
  12697. else
  12698. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12699. }
  12700. else if( op == ttStarStar )
  12701. {
  12702. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12703. if( v == HUGE_VAL )
  12704. Error(TXT_POW_OVERFLOW, node);
  12705. }
  12706. ctx->type.SetConstantF(lctx->type.dataType, v);
  12707. }
  12708. else if( lctx->type.dataType.IsDoubleType() )
  12709. {
  12710. double v = 0.0;
  12711. if( rctx->type.dataType.IsIntegerType() )
  12712. {
  12713. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12714. if( op == ttStarStar || op == ttPowAssign )
  12715. {
  12716. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  12717. if( v == HUGE_VAL )
  12718. Error(TXT_POW_OVERFLOW, node);
  12719. }
  12720. else
  12721. asASSERT(false); // Should not be possible
  12722. }
  12723. else
  12724. {
  12725. if( op == ttPlus )
  12726. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  12727. else if( op == ttMinus )
  12728. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12729. else if( op == ttStar )
  12730. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  12731. else if( op == ttSlash )
  12732. {
  12733. if( rctx->type.GetConstantD() == 0 )
  12734. v = 0;
  12735. else
  12736. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  12737. }
  12738. else if( op == ttPercent )
  12739. {
  12740. if( rctx->type.GetConstantD() == 0 )
  12741. v = 0;
  12742. else
  12743. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12744. }
  12745. else if( op == ttStarStar )
  12746. {
  12747. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12748. if( v == HUGE_VAL )
  12749. Error(TXT_POW_OVERFLOW, node);
  12750. }
  12751. }
  12752. ctx->type.SetConstantD(lctx->type.dataType, v);
  12753. }
  12754. else
  12755. {
  12756. // Shouldn't be possible
  12757. asASSERT(false);
  12758. }
  12759. }
  12760. }
  12761. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12762. {
  12763. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12764. if( op == ttUnrecognizedToken )
  12765. op = node->tokenType;
  12766. if( op == ttAmp || op == ttAndAssign ||
  12767. op == ttBitOr || op == ttOrAssign ||
  12768. op == ttBitXor || op == ttXorAssign )
  12769. {
  12770. // Also do not permit float/double to be implicitly converted to integer in this case
  12771. // as the user may think the result is a bitwise operation on the float value but it's not
  12772. if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType())
  12773. {
  12774. asCString str;
  12775. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12776. Error(str, node);
  12777. // Set an integer value and allow the compiler to continue
  12778. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12779. return;
  12780. }
  12781. if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType())
  12782. {
  12783. asCString str;
  12784. str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12785. Error(str, node);
  12786. // Set an integer value and allow the compiler to continue
  12787. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12788. return;
  12789. }
  12790. // Convert left hand operand to integer if it's not already one
  12791. asCDataType to;
  12792. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  12793. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12794. to.SetTokenType(ttInt64);
  12795. else
  12796. to.SetTokenType(ttInt);
  12797. // Do the actual conversion (keep sign/unsigned if possible)
  12798. int l = int(reservedVariables.GetLength());
  12799. rctx->bc.GetVarsUsed(reservedVariables);
  12800. if( lctx->type.dataType.IsUnsignedType() )
  12801. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12802. else
  12803. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12804. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12805. reservedVariables.SetLength(l);
  12806. // Verify that the conversion was successful
  12807. if( lctx->type.dataType != to )
  12808. {
  12809. asCString str;
  12810. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12811. Error(str, node);
  12812. }
  12813. // Convert right hand operand to same size as left hand
  12814. l = int(reservedVariables.GetLength());
  12815. lctx->bc.GetVarsUsed(reservedVariables);
  12816. if( rctx->type.dataType.IsUnsignedType() )
  12817. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12818. else
  12819. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12820. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12821. reservedVariables.SetLength(l);
  12822. if( rctx->type.dataType != to )
  12823. {
  12824. asCString str;
  12825. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12826. Error(str, node);
  12827. }
  12828. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12829. if( !isConstant )
  12830. {
  12831. ConvertToVariableNotIn(lctx, rctx);
  12832. ConvertToVariableNotIn(rctx, lctx);
  12833. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12834. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12835. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  12836. {
  12837. // Compound assignments execute the right hand value first
  12838. MergeExprBytecode(ctx, rctx);
  12839. MergeExprBytecode(ctx, lctx);
  12840. }
  12841. else
  12842. {
  12843. MergeExprBytecode(ctx, lctx);
  12844. MergeExprBytecode(ctx, rctx);
  12845. }
  12846. ProcessDeferredParams(ctx);
  12847. asEBCInstr instruction = asBC_BAND;
  12848. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12849. {
  12850. if( op == ttAmp || op == ttAndAssign )
  12851. instruction = asBC_BAND;
  12852. else if( op == ttBitOr || op == ttOrAssign )
  12853. instruction = asBC_BOR;
  12854. else if( op == ttBitXor || op == ttXorAssign )
  12855. instruction = asBC_BXOR;
  12856. }
  12857. else
  12858. {
  12859. if( op == ttAmp || op == ttAndAssign )
  12860. instruction = asBC_BAND64;
  12861. else if( op == ttBitOr || op == ttOrAssign )
  12862. instruction = asBC_BOR64;
  12863. else if( op == ttBitXor || op == ttXorAssign )
  12864. instruction = asBC_BXOR64;
  12865. }
  12866. // Do the operation
  12867. int a = AllocateVariable(lctx->type.dataType, true);
  12868. int b = lctx->type.stackOffset;
  12869. int c = rctx->type.stackOffset;
  12870. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12871. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12872. }
  12873. else
  12874. {
  12875. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12876. {
  12877. asQWORD v = 0;
  12878. if( op == ttAmp )
  12879. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  12880. else if( op == ttBitOr )
  12881. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  12882. else if( op == ttBitXor )
  12883. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  12884. // Remember the result
  12885. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12886. }
  12887. else
  12888. {
  12889. asDWORD v = 0;
  12890. if( op == ttAmp )
  12891. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  12892. else if( op == ttBitOr )
  12893. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  12894. else if( op == ttBitXor )
  12895. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  12896. // Remember the result
  12897. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12898. }
  12899. }
  12900. }
  12901. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12902. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12903. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12904. {
  12905. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  12906. // Also do not permit float/double to be implicitly converted to integer in this case
  12907. if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() )
  12908. {
  12909. asCString str;
  12910. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12911. Error(str, node);
  12912. // Set an integer value and allow the compiler to continue
  12913. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12914. return;
  12915. }
  12916. // Convert left hand operand to integer if it's not already one
  12917. asCDataType to = lctx->type.dataType;
  12918. if( lctx->type.dataType.IsUnsignedType() &&
  12919. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  12920. {
  12921. // Upgrade to 32bit
  12922. to = asCDataType::CreatePrimitive(ttUInt, false);
  12923. }
  12924. else if( !lctx->type.dataType.IsUnsignedType() )
  12925. {
  12926. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  12927. to = asCDataType::CreatePrimitive(ttInt64, false);
  12928. else
  12929. to = asCDataType::CreatePrimitive(ttInt, false);
  12930. }
  12931. // Do the actual conversion
  12932. int l = int(reservedVariables.GetLength());
  12933. rctx->bc.GetVarsUsed(reservedVariables);
  12934. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12935. reservedVariables.SetLength(l);
  12936. // Verify that the conversion was successful
  12937. if( lctx->type.dataType != to )
  12938. {
  12939. asCString str;
  12940. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12941. Error(str, node);
  12942. }
  12943. // Right operand must be 32bit uint
  12944. l = int(reservedVariables.GetLength());
  12945. lctx->bc.GetVarsUsed(reservedVariables);
  12946. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  12947. reservedVariables.SetLength(l);
  12948. if( !rctx->type.dataType.IsUnsignedType() )
  12949. {
  12950. asCString str;
  12951. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  12952. Error(str, node);
  12953. }
  12954. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12955. if( !isConstant )
  12956. {
  12957. ConvertToVariableNotIn(lctx, rctx);
  12958. ConvertToVariableNotIn(rctx, lctx);
  12959. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12960. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12961. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  12962. {
  12963. // Compound assignments execute the right hand value first
  12964. MergeExprBytecode(ctx, rctx);
  12965. MergeExprBytecode(ctx, lctx);
  12966. }
  12967. else
  12968. {
  12969. MergeExprBytecode(ctx, lctx);
  12970. MergeExprBytecode(ctx, rctx);
  12971. }
  12972. ProcessDeferredParams(ctx);
  12973. asEBCInstr instruction = asBC_BSLL;
  12974. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12975. {
  12976. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12977. instruction = asBC_BSLL;
  12978. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12979. instruction = asBC_BSRL;
  12980. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12981. instruction = asBC_BSRA;
  12982. }
  12983. else
  12984. {
  12985. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12986. instruction = asBC_BSLL64;
  12987. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12988. instruction = asBC_BSRL64;
  12989. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12990. instruction = asBC_BSRA64;
  12991. }
  12992. // Do the operation
  12993. int a = AllocateVariable(lctx->type.dataType, true);
  12994. int b = lctx->type.stackOffset;
  12995. int c = rctx->type.stackOffset;
  12996. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12997. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12998. }
  12999. else
  13000. {
  13001. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13002. {
  13003. asDWORD v = 0;
  13004. if( op == ttBitShiftLeft )
  13005. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  13006. else if( op == ttBitShiftRight )
  13007. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  13008. else if( op == ttBitShiftRightArith )
  13009. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  13010. ctx->type.SetConstantDW(lctx->type.dataType, v);
  13011. }
  13012. else
  13013. {
  13014. asQWORD v = 0;
  13015. if( op == ttBitShiftLeft )
  13016. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  13017. else if( op == ttBitShiftRight )
  13018. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  13019. else if( op == ttBitShiftRightArith )
  13020. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  13021. ctx->type.SetConstantQW(lctx->type.dataType, v);
  13022. }
  13023. }
  13024. }
  13025. }
  13026. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  13027. {
  13028. // Both operands must be of the same type
  13029. // If either operand is a non-primitive then first convert them to the best number type
  13030. if( !lctx->type.dataType.IsPrimitive() )
  13031. {
  13032. int l = int(reservedVariables.GetLength());
  13033. rctx->bc.GetVarsUsed(reservedVariables);
  13034. ImplicitConvObjectToBestMathType(lctx, node);
  13035. reservedVariables.SetLength(l);
  13036. }
  13037. if( !rctx->type.dataType.IsPrimitive() )
  13038. {
  13039. int l = int(reservedVariables.GetLength());
  13040. lctx->bc.GetVarsUsed(reservedVariables);
  13041. ImplicitConvObjectToBestMathType(rctx, node);
  13042. reservedVariables.SetLength(l);
  13043. }
  13044. // Implicitly convert the operands to matching types
  13045. asCDataType to;
  13046. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  13047. to.SetTokenType(ttDouble);
  13048. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  13049. to.SetTokenType(ttFloat);
  13050. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13051. {
  13052. // Convert to int64 if both are signed or if one is non-constant and signed
  13053. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  13054. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  13055. to.SetTokenType(ttInt64);
  13056. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  13057. to.SetTokenType(ttUInt64);
  13058. else
  13059. to.SetTokenType(ttInt64);
  13060. }
  13061. else
  13062. {
  13063. // Convert to int32 if both are signed or if one is non-constant and signed
  13064. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  13065. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  13066. to.SetTokenType(ttInt);
  13067. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  13068. to.SetTokenType(ttUInt);
  13069. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  13070. to.SetTokenType(ttBool);
  13071. else
  13072. to.SetTokenType(ttInt);
  13073. }
  13074. // If doing an operation with double constant and float variable, the constant should be converted to float
  13075. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  13076. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  13077. to.SetTokenType(ttFloat);
  13078. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  13079. // Do we have a mismatch between the sign of the operand?
  13080. bool signMismatch = false;
  13081. for( int n = 0; !signMismatch && n < 2; n++ )
  13082. {
  13083. asCExprContext *opCtx = n ? rctx : lctx;
  13084. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  13085. {
  13086. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  13087. signMismatch = true;
  13088. if( opCtx->type.isConstant )
  13089. {
  13090. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  13091. {
  13092. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  13093. signMismatch = false;
  13094. }
  13095. else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
  13096. {
  13097. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  13098. signMismatch = false;
  13099. }
  13100. else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
  13101. {
  13102. if (!(opCtx->type.GetConstantW() & (1 << 15)))
  13103. signMismatch = false;
  13104. }
  13105. else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
  13106. {
  13107. if (!(opCtx->type.GetConstantB() & (1 << 7)))
  13108. signMismatch = false;
  13109. }
  13110. // It's not necessary to check for floats or double, because if
  13111. // it was then the types for the conversion will never be unsigned
  13112. }
  13113. }
  13114. }
  13115. // Check for signed/unsigned mismatch
  13116. if( signMismatch )
  13117. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  13118. // Attempt to resolve ambiguous enumerations
  13119. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  13120. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13121. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  13122. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13123. // Do the actual conversion
  13124. int l = int(reservedVariables.GetLength());
  13125. rctx->bc.GetVarsUsed(reservedVariables);
  13126. if( lctx->type.dataType.IsReference() )
  13127. ConvertToVariable(lctx);
  13128. if( rctx->type.dataType.IsReference() )
  13129. ConvertToVariable(rctx);
  13130. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13131. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13132. reservedVariables.SetLength(l);
  13133. // Verify that the conversion was successful
  13134. bool ok = true;
  13135. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13136. {
  13137. asCString str;
  13138. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13139. Error(str, node);
  13140. ok = false;
  13141. }
  13142. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13143. {
  13144. asCString str;
  13145. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13146. Error(str, node);
  13147. ok = false;
  13148. }
  13149. if( !ok )
  13150. {
  13151. // It wasn't possible to get two valid operands, so we just return
  13152. // a boolean result and let the compiler continue.
  13153. #if AS_SIZEOF_BOOL == 1
  13154. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13155. #else
  13156. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13157. #endif
  13158. return;
  13159. }
  13160. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13161. if( op == ttUnrecognizedToken )
  13162. op = node->tokenType;
  13163. if( !isConstant )
  13164. {
  13165. if( to.IsBooleanType() )
  13166. {
  13167. if( op == ttEqual || op == ttNotEqual )
  13168. {
  13169. // Must convert to temporary variable, because we are changing the value before comparison
  13170. ConvertToTempVariableNotIn(lctx, rctx);
  13171. ConvertToTempVariableNotIn(rctx, lctx);
  13172. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13173. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13174. // Make sure they are equal if not false
  13175. lctx->bc.InstrWORD(asBC_NOT, (short)lctx->type.stackOffset);
  13176. rctx->bc.InstrWORD(asBC_NOT, (short)rctx->type.stackOffset);
  13177. MergeExprBytecode(ctx, lctx);
  13178. MergeExprBytecode(ctx, rctx);
  13179. ProcessDeferredParams(ctx);
  13180. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13181. int b = lctx->type.stackOffset;
  13182. int c = rctx->type.stackOffset;
  13183. if( op == ttEqual )
  13184. {
  13185. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13186. ctx->bc.Instr(asBC_TZ);
  13187. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13188. }
  13189. else if( op == ttNotEqual )
  13190. {
  13191. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13192. ctx->bc.Instr(asBC_TNZ);
  13193. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13194. }
  13195. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13196. }
  13197. else
  13198. {
  13199. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13200. Error(TXT_ILLEGAL_OPERATION, node);
  13201. #if AS_SIZEOF_BOOL == 1
  13202. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  13203. #else
  13204. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  13205. #endif
  13206. }
  13207. }
  13208. else
  13209. {
  13210. ConvertToVariableNotIn(lctx, rctx);
  13211. ConvertToVariableNotIn(rctx, lctx);
  13212. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13213. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13214. MergeExprBytecode(ctx, lctx);
  13215. MergeExprBytecode(ctx, rctx);
  13216. ProcessDeferredParams(ctx);
  13217. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  13218. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13219. iCmp = asBC_CMPi;
  13220. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13221. iCmp = asBC_CMPu;
  13222. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13223. iCmp = asBC_CMPi64;
  13224. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13225. iCmp = asBC_CMPu64;
  13226. else if( lctx->type.dataType.IsFloatType() )
  13227. iCmp = asBC_CMPf;
  13228. else if( lctx->type.dataType.IsDoubleType() )
  13229. iCmp = asBC_CMPd;
  13230. else
  13231. asASSERT(false);
  13232. if( op == ttEqual )
  13233. iT = asBC_TZ;
  13234. else if( op == ttNotEqual )
  13235. iT = asBC_TNZ;
  13236. else if( op == ttLessThan )
  13237. iT = asBC_TS;
  13238. else if( op == ttLessThanOrEqual )
  13239. iT = asBC_TNP;
  13240. else if( op == ttGreaterThan )
  13241. iT = asBC_TP;
  13242. else if( op == ttGreaterThanOrEqual )
  13243. iT = asBC_TNS;
  13244. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13245. int b = lctx->type.stackOffset;
  13246. int c = rctx->type.stackOffset;
  13247. ctx->bc.InstrW_W(iCmp, b, c);
  13248. ctx->bc.Instr(iT);
  13249. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13250. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13251. }
  13252. }
  13253. else
  13254. {
  13255. if( to.IsBooleanType() )
  13256. {
  13257. if( op == ttEqual || op == ttNotEqual )
  13258. {
  13259. asDWORD lv, rv;
  13260. #if AS_SIZEOF_BOOL == 1
  13261. lv = lctx->type.GetConstantB();
  13262. rv = rctx->type.GetConstantB();
  13263. #else
  13264. lv = lctx->type.GetConstantDW();
  13265. rv = rctx->type.GetConstantDW();
  13266. #endif
  13267. // Make sure they are equal if not false
  13268. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  13269. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  13270. asDWORD v = 0;
  13271. if (op == ttEqual)
  13272. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13273. else if (op == ttNotEqual)
  13274. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13275. #if AS_SIZEOF_BOOL == 1
  13276. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  13277. #else
  13278. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  13279. #endif
  13280. }
  13281. else
  13282. {
  13283. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13284. Error(TXT_ILLEGAL_OPERATION, node);
  13285. }
  13286. }
  13287. else
  13288. {
  13289. int i = 0;
  13290. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13291. {
  13292. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  13293. if( v < 0 ) i = -1;
  13294. if( v > 0 ) i = 1;
  13295. }
  13296. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13297. {
  13298. asDWORD v1 = lctx->type.GetConstantDW();
  13299. asDWORD v2 = rctx->type.GetConstantDW();
  13300. if( v1 < v2 ) i = -1;
  13301. if( v1 > v2 ) i = 1;
  13302. }
  13303. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13304. {
  13305. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  13306. if( v < 0 ) i = -1;
  13307. if( v > 0 ) i = 1;
  13308. }
  13309. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13310. {
  13311. asQWORD v1 = lctx->type.GetConstantQW();
  13312. asQWORD v2 = rctx->type.GetConstantQW();
  13313. if( v1 < v2 ) i = -1;
  13314. if( v1 > v2 ) i = 1;
  13315. }
  13316. else if( lctx->type.dataType.IsFloatType() )
  13317. {
  13318. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  13319. if( v < 0 ) i = -1;
  13320. if( v > 0 ) i = 1;
  13321. }
  13322. else if( lctx->type.dataType.IsDoubleType() )
  13323. {
  13324. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  13325. if( v < 0 ) i = -1;
  13326. if( v > 0 ) i = 1;
  13327. }
  13328. if( op == ttEqual )
  13329. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13330. else if( op == ttNotEqual )
  13331. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13332. else if( op == ttLessThan )
  13333. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13334. else if( op == ttLessThanOrEqual )
  13335. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13336. else if( op == ttGreaterThan )
  13337. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13338. else if( op == ttGreaterThanOrEqual )
  13339. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13340. #if AS_SIZEOF_BOOL == 1
  13341. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  13342. #else
  13343. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  13344. #endif
  13345. }
  13346. }
  13347. }
  13348. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  13349. {
  13350. // Put the result on the stack
  13351. if( asReference )
  13352. {
  13353. ctx->bc.InstrSHORT(asBC_PSF, (short)ctx->type.stackOffset);
  13354. ctx->type.dataType.MakeReference(true);
  13355. }
  13356. else
  13357. {
  13358. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13359. ctx->bc.InstrSHORT(asBC_PshV4, (short)ctx->type.stackOffset);
  13360. else
  13361. ctx->bc.InstrSHORT(asBC_PshV8, (short)ctx->type.stackOffset);
  13362. }
  13363. }
  13364. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  13365. {
  13366. // Both operands must be booleans
  13367. asCDataType to;
  13368. to.SetTokenType(ttBool);
  13369. // Do the actual conversion
  13370. int l = int(reservedVariables.GetLength());
  13371. rctx->bc.GetVarsUsed(reservedVariables);
  13372. lctx->bc.GetVarsUsed(reservedVariables);
  13373. // Allow value types to be converted to bool using 'bool opImplConv()'
  13374. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13375. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13376. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13377. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13378. reservedVariables.SetLength(l);
  13379. // Verify that the conversion was successful
  13380. if( !lctx->type.dataType.IsBooleanType() )
  13381. {
  13382. asCString str;
  13383. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13384. Error(str, node);
  13385. // Force the conversion to allow compilation to proceed
  13386. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13387. }
  13388. if( !rctx->type.dataType.IsBooleanType() )
  13389. {
  13390. asCString str;
  13391. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13392. Error(str, node);
  13393. // Force the conversion to allow compilation to proceed
  13394. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13395. }
  13396. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13397. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13398. // What kind of operator is it?
  13399. if( op == ttUnrecognizedToken )
  13400. op = node->tokenType;
  13401. if( op == ttXor )
  13402. {
  13403. if( !isConstant )
  13404. {
  13405. // Must convert to temporary variable, because we are changing the value before comparison
  13406. ConvertToTempVariableNotIn(lctx, rctx);
  13407. ConvertToTempVariableNotIn(rctx, lctx);
  13408. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13409. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13410. // Make sure they are equal if not false
  13411. lctx->bc.InstrWORD(asBC_NOT, (short)lctx->type.stackOffset);
  13412. rctx->bc.InstrWORD(asBC_NOT, (short)rctx->type.stackOffset);
  13413. MergeExprBytecode(ctx, lctx);
  13414. MergeExprBytecode(ctx, rctx);
  13415. ProcessDeferredParams(ctx);
  13416. int a = AllocateVariable(ctx->type.dataType, true);
  13417. int b = lctx->type.stackOffset;
  13418. int c = rctx->type.stackOffset;
  13419. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  13420. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13421. }
  13422. else
  13423. {
  13424. // Make sure they are equal if not false
  13425. #if AS_SIZEOF_BOOL == 1
  13426. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13427. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13428. asBYTE v = 0;
  13429. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  13430. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13431. ctx->type.isConstant = true;
  13432. ctx->type.SetConstantB(v);
  13433. #else
  13434. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13435. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13436. asDWORD v = 0;
  13437. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  13438. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13439. ctx->type.isConstant = true;
  13440. ctx->type.SetConstantDW(v);
  13441. #endif
  13442. }
  13443. }
  13444. else if( op == ttAnd ||
  13445. op == ttOr )
  13446. {
  13447. if( !isConstant )
  13448. {
  13449. // If or-operator and first value is 1 the second value shouldn't be calculated
  13450. // if and-operator and first value is 0 the second value shouldn't be calculated
  13451. ConvertToVariable(lctx);
  13452. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13453. MergeExprBytecode(ctx, lctx);
  13454. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  13455. int label1 = nextLabel++;
  13456. int label2 = nextLabel++;
  13457. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)lctx->type.stackOffset);
  13458. ctx->bc.Instr(asBC_ClrHi);
  13459. if( op == ttAnd )
  13460. {
  13461. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  13462. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  13463. ctx->bc.InstrINT(asBC_JMP, label2);
  13464. }
  13465. else if( op == ttOr )
  13466. {
  13467. ctx->bc.InstrDWORD(asBC_JZ, label1);
  13468. #if AS_SIZEOF_BOOL == 1
  13469. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13470. #else
  13471. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13472. #endif
  13473. ctx->bc.InstrINT(asBC_JMP, label2);
  13474. }
  13475. ctx->bc.Label((short)label1);
  13476. ConvertToVariable(rctx);
  13477. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13478. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  13479. // Make sure temporary variables created within this expression are destroyed within it.
  13480. // Without this, the compiler would add the code to clean-up the temporary variables after the label,
  13481. // which means the clean-up code might be executed without the variables actually being created first.
  13482. // This is especially true when unsafe references is turned on as then destruction of temporaries
  13483. // will be deferred to the end of expressions by default.
  13484. ProcessDeferredParams(rctx);
  13485. MergeExprBytecode(ctx, rctx);
  13486. ctx->bc.Label((short)label2);
  13487. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  13488. }
  13489. else
  13490. {
  13491. #if AS_SIZEOF_BOOL == 1
  13492. asBYTE v = 0;
  13493. if( op == ttAnd )
  13494. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  13495. else if( op == ttOr )
  13496. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  13497. // Remember the result
  13498. ctx->type.isConstant = true;
  13499. ctx->type.SetConstantB(v);
  13500. #else
  13501. asDWORD v = 0;
  13502. if( op == ttAnd )
  13503. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  13504. else if( op == ttOr )
  13505. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  13506. // Remember the result
  13507. ctx->type.isConstant = true;
  13508. ctx->type.SetConstantDW(v);
  13509. #endif
  13510. }
  13511. }
  13512. }
  13513. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  13514. {
  13515. // Process the property accessor as get
  13516. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  13517. return;
  13518. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  13519. return;
  13520. DetermineSingleFunc(lctx, node);
  13521. DetermineSingleFunc(rctx, node);
  13522. // Make sure lctx doesn't end up with a variable used in rctx
  13523. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  13524. {
  13525. asCArray<int> vars;
  13526. rctx->bc.GetVarsUsed(vars);
  13527. int offset = AllocateVariable(lctx->type.dataType, true);
  13528. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  13529. ReleaseTemporaryVariable(offset, 0);
  13530. }
  13531. if( opToken == ttUnrecognizedToken )
  13532. opToken = node->tokenType;
  13533. // Warn if not both operands are explicit handles or null handles
  13534. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  13535. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  13536. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  13537. {
  13538. Warning(TXT_HANDLE_COMPARISON, node);
  13539. }
  13540. // If one of the operands is a value type used as handle, we should look for the opEquals method
  13541. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  13542. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  13543. (opToken == ttEqual || opToken == ttIs ||
  13544. opToken == ttNotEqual || opToken == ttNotIs) )
  13545. {
  13546. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  13547. // Find the matching opEquals method
  13548. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13549. if( r == 0 )
  13550. {
  13551. // Try again by switching the order of the operands
  13552. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13553. }
  13554. if( r == 1 )
  13555. {
  13556. if( opToken == ttNotEqual || opToken == ttNotIs )
  13557. ctx->bc.InstrSHORT(asBC_NOT, (short)ctx->type.stackOffset);
  13558. // Success, don't continue
  13559. return;
  13560. }
  13561. else if( r == 0 )
  13562. {
  13563. // Couldn't find opEquals method
  13564. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  13565. }
  13566. // Compiler error, don't continue
  13567. #if AS_SIZEOF_BOOL == 1
  13568. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13569. #else
  13570. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13571. #endif
  13572. return;
  13573. }
  13574. // Implicitly convert null to the other type
  13575. asCDataType to;
  13576. if( lctx->type.IsNullConstant() )
  13577. to = rctx->type.dataType;
  13578. else if( rctx->type.IsNullConstant() )
  13579. to = lctx->type.dataType;
  13580. else
  13581. {
  13582. // Find a common base type
  13583. asCExprContext tmp(engine);
  13584. tmp.type = rctx->type;
  13585. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  13586. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  13587. to = lctx->type.dataType;
  13588. else
  13589. to = rctx->type.dataType;
  13590. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  13591. to.MakeHandleToConst(true);
  13592. }
  13593. // Need to pop the value if it is a null constant
  13594. if( lctx->type.IsNullConstant() )
  13595. lctx->bc.Instr(asBC_PopPtr);
  13596. if( rctx->type.IsNullConstant() )
  13597. rctx->bc.Instr(asBC_PopPtr);
  13598. // Convert both sides to explicit handles
  13599. to.MakeHandle(true);
  13600. to.MakeReference(false);
  13601. if( !to.IsObjectHandle() )
  13602. {
  13603. // Compiler error, don't continue
  13604. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13605. #if AS_SIZEOF_BOOL == 1
  13606. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13607. #else
  13608. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13609. #endif
  13610. return;
  13611. }
  13612. // Do the conversion
  13613. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13614. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13615. // Both operands must be of the same type
  13616. // Verify that the conversion was successful
  13617. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13618. {
  13619. asCString str;
  13620. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13621. Error(str, node);
  13622. }
  13623. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13624. {
  13625. asCString str;
  13626. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13627. Error(str, node);
  13628. }
  13629. // Make sure it really is handles that are being compared
  13630. if( !lctx->type.dataType.IsObjectHandle() )
  13631. {
  13632. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13633. }
  13634. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13635. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  13636. {
  13637. // Make sure handles received as parameters by reference are copied to a local variable before the
  13638. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  13639. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  13640. lctx->type.isVariable = false;
  13641. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  13642. rctx->type.isVariable = false;
  13643. // TODO: runtime optimize: don't do REFCPY if not necessary
  13644. ConvertToVariableNotIn(lctx, rctx);
  13645. ConvertToVariable(rctx);
  13646. // Pop the pointers from the stack as they will not be used
  13647. lctx->bc.Instr(asBC_PopPtr);
  13648. rctx->bc.Instr(asBC_PopPtr);
  13649. MergeExprBytecode(ctx, lctx);
  13650. MergeExprBytecode(ctx, rctx);
  13651. int a = AllocateVariable(ctx->type.dataType, true);
  13652. int b = lctx->type.stackOffset;
  13653. int c = rctx->type.stackOffset;
  13654. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  13655. if( opToken == ttEqual || opToken == ttIs )
  13656. ctx->bc.Instr(asBC_TZ);
  13657. else if( opToken == ttNotEqual || opToken == ttNotIs )
  13658. ctx->bc.Instr(asBC_TNZ);
  13659. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13660. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13661. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  13662. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  13663. ProcessDeferredParams(ctx);
  13664. }
  13665. else
  13666. {
  13667. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13668. Error(TXT_ILLEGAL_OPERATION, node);
  13669. }
  13670. }
  13671. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  13672. {
  13673. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  13674. // A shared object may not call non-shared functions
  13675. if( outFunc->IsShared() && !descr->IsShared() )
  13676. {
  13677. asCString msg;
  13678. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  13679. Error(msg, ctx->exprNode);
  13680. }
  13681. // Check if the function is private or protected
  13682. if (descr->IsPrivate())
  13683. {
  13684. asCObjectType *type = descr->objectType;
  13685. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13686. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13687. asASSERT(type);
  13688. if( (type != outFunc->GetObjectType()) )
  13689. {
  13690. asCString msg;
  13691. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13692. Error(msg, ctx->exprNode);
  13693. }
  13694. }
  13695. else if (descr->IsProtected())
  13696. {
  13697. asCObjectType *type = descr->objectType;
  13698. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13699. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13700. asASSERT(type);
  13701. if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type))))
  13702. {
  13703. asCString msg;
  13704. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13705. Error(msg, ctx->exprNode);
  13706. }
  13707. }
  13708. int argSize = descr->GetSpaceNeededForArguments();
  13709. // If we're calling a class method we must make sure the object is guaranteed to stay
  13710. // alive throughout the call by holding on to a reference in a local variable. This must
  13711. // be done for any methods that return references, and any calls on script objects.
  13712. // Application registered objects are assumed to know to keep themselves alive even
  13713. // if the method doesn't return a reference.
  13714. if( !ctx->type.isRefSafe &&
  13715. descr->objectType &&
  13716. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  13717. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  13718. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  13719. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  13720. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  13721. {
  13722. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  13723. // local variable and then refer to the same for each call. An alias for the global variable
  13724. // should be stored in the variable scope so that the compiler can find it. For loops and
  13725. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  13726. // higher scope to increase the probability of re-use.
  13727. int tempRef = AllocateVariable(ctx->type.dataType, true);
  13728. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  13729. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  13730. // Add the release of this reference as a deferred expression
  13731. asSDeferredParam deferred;
  13732. deferred.origExpr = 0;
  13733. deferred.argInOutFlags = asTM_INREF;
  13734. deferred.argNode = 0;
  13735. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  13736. ctx->deferredParams.PushLast(deferred);
  13737. // Forget the current type
  13738. ctx->type.SetDummy();
  13739. }
  13740. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  13741. if( descr->DoesReturnOnStack() && !useVariable )
  13742. {
  13743. useVariable = true;
  13744. varOffset = AllocateVariable(descr->returnType, true);
  13745. // Push the pointer to the pre-allocated space for the return value
  13746. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  13747. if( descr->objectType )
  13748. {
  13749. // The object pointer is already on the stack, but should be the top
  13750. // one, so we need to swap the pointers in order to get the correct
  13751. ctx->bc.Instr(asBC_SwapPtr);
  13752. }
  13753. }
  13754. if( isConstructor )
  13755. {
  13756. // Sometimes the value types are allocated on the heap,
  13757. // which is when this way of constructing them is used.
  13758. asASSERT(useVariable == false);
  13759. if( (objType->flags & asOBJ_TEMPLATE) )
  13760. {
  13761. asASSERT( descr->funcType == asFUNC_SCRIPT );
  13762. // Find the id of the real constructor and not the generated stub
  13763. asUINT id = 0;
  13764. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  13765. while( bc )
  13766. {
  13767. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  13768. {
  13769. id = asBC_INTARG(bc);
  13770. break;
  13771. }
  13772. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  13773. }
  13774. asASSERT( id );
  13775. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  13776. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  13777. }
  13778. else
  13779. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  13780. // The instruction has already moved the returned object to the variable
  13781. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  13782. ctx->type.isLValue = false;
  13783. // Clean up arguments
  13784. if( args )
  13785. AfterFunctionCall(funcId, *args, ctx, false);
  13786. ProcessDeferredParams(ctx);
  13787. return;
  13788. }
  13789. else
  13790. {
  13791. if( descr->objectType )
  13792. argSize += AS_PTR_SIZE;
  13793. // If the function returns an object by value the address of the location
  13794. // where the value should be stored is passed as an argument too
  13795. if( descr->DoesReturnOnStack() )
  13796. argSize += AS_PTR_SIZE;
  13797. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  13798. // should be made with asBC_CALL as it is faster. Examples where this
  13799. // is known is for example finalled methods where the class doesn't derive
  13800. // from any other, or even non-finalled methods but where it is known
  13801. // at compile time the true type of the object. The first should be
  13802. // quite easy to determine, but the latter will be quite complex and possibly
  13803. // not worth it.
  13804. if( descr->funcType == asFUNC_IMPORTED )
  13805. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  13806. // TODO: Maybe we need two different byte codes
  13807. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  13808. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  13809. else if( descr->funcType == asFUNC_SCRIPT )
  13810. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  13811. else if( descr->funcType == asFUNC_SYSTEM )
  13812. {
  13813. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  13814. // type &obj::func(int)
  13815. // type &obj::func(uint)
  13816. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  13817. descr->parameterTypes.GetLength() == 1 &&
  13818. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  13819. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  13820. !descr->parameterTypes[0].IsReference() )
  13821. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  13822. else
  13823. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  13824. }
  13825. else if( descr->funcType == asFUNC_FUNCDEF )
  13826. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  13827. }
  13828. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  13829. {
  13830. int returnOffset = 0;
  13831. asCExprValue tmpExpr = ctx->type;
  13832. if( descr->DoesReturnOnStack() )
  13833. {
  13834. asASSERT( useVariable );
  13835. // The variable was allocated before the function was called
  13836. returnOffset = varOffset;
  13837. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13838. // The variable was initialized by the function, so we need to mark it as initialized here
  13839. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  13840. }
  13841. else
  13842. {
  13843. if( useVariable )
  13844. {
  13845. // Use the given variable
  13846. returnOffset = varOffset;
  13847. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  13848. }
  13849. else
  13850. {
  13851. // Allocate a temporary variable for the returned object
  13852. // The returned object will actually be allocated on the heap, so
  13853. // we must force the allocation of the variable to do the same
  13854. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  13855. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13856. }
  13857. // Move the pointer from the object register to the temporary variable
  13858. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  13859. }
  13860. // If the context holds a variable that needs cleanup and the application uses unsafe
  13861. // references then store it as a deferred parameter so it will be cleaned up afterwards.
  13862. if (tmpExpr.isTemporary && engine->ep.allowUnsafeReferences)
  13863. {
  13864. asSDeferredParam defer;
  13865. defer.argNode = 0;
  13866. defer.argType = tmpExpr;
  13867. defer.argInOutFlags = asTM_INOUTREF;
  13868. defer.origExpr = 0;
  13869. ctx->deferredParams.PushLast(defer);
  13870. }
  13871. else
  13872. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13873. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  13874. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  13875. // Clean up arguments
  13876. // If application is using unsafe references, then don't clean up arguments yet because
  13877. // the returned object might be referencing one of the arguments.
  13878. if( args )
  13879. AfterFunctionCall(funcId, *args, ctx, engine->ep.allowUnsafeReferences ? true : false);
  13880. if (!engine->ep.allowUnsafeReferences)
  13881. ProcessDeferredParams(ctx);
  13882. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  13883. }
  13884. else if( descr->returnType.IsReference() )
  13885. {
  13886. asASSERT(useVariable == false);
  13887. // We cannot clean up the arguments yet, because the
  13888. // reference might be pointing to one of them.
  13889. if( args )
  13890. AfterFunctionCall(funcId, *args, ctx, true);
  13891. // Do not process the output parameters yet, because it
  13892. // might invalidate the returned reference
  13893. // If the context holds a variable that needs cleanup
  13894. // store it as a deferred parameter so it will be cleaned up
  13895. // afterwards.
  13896. if( ctx->type.isTemporary )
  13897. {
  13898. asSDeferredParam defer;
  13899. defer.argNode = 0;
  13900. defer.argType = ctx->type;
  13901. defer.argInOutFlags = asTM_INOUTREF;
  13902. defer.origExpr = 0;
  13903. ctx->deferredParams.PushLast(defer);
  13904. }
  13905. ctx->type.Set(descr->returnType);
  13906. if( !descr->returnType.IsPrimitive() )
  13907. {
  13908. ctx->bc.Instr(asBC_PshRPtr);
  13909. if( descr->returnType.IsObject() &&
  13910. !descr->returnType.IsObjectHandle() )
  13911. {
  13912. // We are getting the pointer to the object
  13913. // not a pointer to a object variable
  13914. ctx->type.dataType.MakeReference(false);
  13915. }
  13916. }
  13917. // A returned reference can be used as lvalue
  13918. ctx->type.isLValue = true;
  13919. }
  13920. else
  13921. {
  13922. asCExprValue tmpExpr = ctx->type;
  13923. if( descr->returnType.GetSizeInMemoryBytes() )
  13924. {
  13925. int offset;
  13926. if (useVariable)
  13927. offset = varOffset;
  13928. else
  13929. {
  13930. // Allocate a temporary variable to hold the value, but make sure
  13931. // the temporary variable isn't used in any of the deferred arguments
  13932. int l = int(reservedVariables.GetLength());
  13933. for (asUINT n = 0; args && n < args->GetLength(); n++)
  13934. {
  13935. asCExprContext *expr = (*args)[n]->origExpr;
  13936. if (expr)
  13937. expr->bc.GetVarsUsed(reservedVariables);
  13938. }
  13939. offset = AllocateVariable(descr->returnType, true);
  13940. reservedVariables.SetLength(l);
  13941. }
  13942. ctx->type.SetVariable(descr->returnType, offset, true);
  13943. // Move the value from the return register to the variable
  13944. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  13945. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  13946. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  13947. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  13948. }
  13949. else
  13950. ctx->type.Set(descr->returnType);
  13951. // If the context holds a variable that needs cleanup and the application uses unsafe
  13952. // references then store it as a deferred parameter so it will be cleaned up afterwards.
  13953. if (tmpExpr.isTemporary && engine->ep.allowUnsafeReferences )
  13954. {
  13955. asSDeferredParam defer;
  13956. defer.argNode = 0;
  13957. defer.argType = tmpExpr;
  13958. defer.argInOutFlags = asTM_INOUTREF;
  13959. defer.origExpr = 0;
  13960. ctx->deferredParams.PushLast(defer);
  13961. }
  13962. else
  13963. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13964. ctx->type.isLValue = false;
  13965. // Clean up arguments
  13966. // If application is using unsafe references, then don't clean up arguments yet because
  13967. // the returned value might represent a reference to one of the arguments, e.g. an integer might in truth be a pointer
  13968. if( args )
  13969. AfterFunctionCall(funcId, *args, ctx, engine->ep.allowUnsafeReferences ? true : false);
  13970. if( !engine->ep.allowUnsafeReferences )
  13971. ProcessDeferredParams(ctx);
  13972. }
  13973. }
  13974. // This only merges the bytecode, but doesn't modify the type of the final context
  13975. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  13976. {
  13977. before->bc.AddCode(&after->bc);
  13978. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  13979. {
  13980. before->deferredParams.PushLast(after->deferredParams[n]);
  13981. after->deferredParams[n].origExpr = 0;
  13982. }
  13983. after->deferredParams.SetLength(0);
  13984. }
  13985. // This merges both bytecode and the type of the final context
  13986. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  13987. {
  13988. MergeExprBytecode(before, after);
  13989. before->Merge(after);
  13990. }
  13991. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  13992. {
  13993. if( funcs.GetLength() == 0 ) return;
  13994. // This is only done for object methods
  13995. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  13996. if( !desc || desc->objectType == 0 ) return;
  13997. // Check if there are any non-const matches
  13998. asUINT n;
  13999. bool foundNonConst = false;
  14000. for( n = 0; n < funcs.GetLength(); n++ )
  14001. {
  14002. desc = builder->GetFunctionDescription(funcs[n]);
  14003. if( desc && desc->IsReadOnly() != removeConst )
  14004. {
  14005. foundNonConst = true;
  14006. break;
  14007. }
  14008. }
  14009. if( foundNonConst )
  14010. {
  14011. // Remove all const methods
  14012. for( n = 0; n < funcs.GetLength(); n++ )
  14013. {
  14014. desc = builder->GetFunctionDescription(funcs[n]);
  14015. if( desc && desc->IsReadOnly() == removeConst )
  14016. {
  14017. if( n == funcs.GetLength() - 1 )
  14018. funcs.PopLast();
  14019. else
  14020. funcs[n] = funcs.PopLast();
  14021. n--;
  14022. }
  14023. }
  14024. }
  14025. }
  14026. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  14027. asCExprValue::asCExprValue()
  14028. {
  14029. isTemporary = false;
  14030. stackOffset = 0;
  14031. isConstant = false;
  14032. isVariable = false;
  14033. isExplicitHandle = false;
  14034. qwordValue = 0;
  14035. isLValue = false;
  14036. isRefToLocal = false;
  14037. isRefSafe = false;
  14038. }
  14039. void asCExprValue::Set(const asCDataType &dt)
  14040. {
  14041. dataType = dt;
  14042. isTemporary = false;
  14043. stackOffset = 0;
  14044. isConstant = false;
  14045. isVariable = false;
  14046. isExplicitHandle = false;
  14047. qwordValue = 0;
  14048. isLValue = false;
  14049. isRefToLocal = false;
  14050. isRefSafe = false;
  14051. }
  14052. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  14053. {
  14054. Set(in_dt);
  14055. this->isVariable = true;
  14056. this->isTemporary = in_isTemporary;
  14057. this->stackOffset = (short)in_stackOffset;
  14058. }
  14059. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  14060. {
  14061. Set(dt);
  14062. isConstant = true;
  14063. SetConstantQW(value);
  14064. }
  14065. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  14066. {
  14067. Set(dt);
  14068. isConstant = true;
  14069. SetConstantDW(value);
  14070. }
  14071. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  14072. {
  14073. Set(dt);
  14074. isConstant = true;
  14075. SetConstantB(value);
  14076. }
  14077. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  14078. {
  14079. Set(dt);
  14080. isConstant = true;
  14081. SetConstantW(value);
  14082. }
  14083. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  14084. {
  14085. Set(dt);
  14086. isConstant = true;
  14087. SetConstantF(value);
  14088. }
  14089. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  14090. {
  14091. Set(dt);
  14092. isConstant = true;
  14093. SetConstantD(value);
  14094. }
  14095. void asCExprValue::SetConstantQW(asQWORD value)
  14096. {
  14097. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14098. qwordValue = value;
  14099. }
  14100. void asCExprValue::SetConstantDW(asDWORD value)
  14101. {
  14102. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14103. dwordValue = value;
  14104. }
  14105. void asCExprValue::SetConstantW(asWORD value)
  14106. {
  14107. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  14108. wordValue = value;
  14109. }
  14110. void asCExprValue::SetConstantB(asBYTE value)
  14111. {
  14112. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  14113. byteValue = value;
  14114. }
  14115. void asCExprValue::SetConstantF(float value)
  14116. {
  14117. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14118. floatValue = value;
  14119. }
  14120. void asCExprValue::SetConstantD(double value)
  14121. {
  14122. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14123. doubleValue = value;
  14124. }
  14125. asQWORD asCExprValue::GetConstantQW()
  14126. {
  14127. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14128. return qwordValue;
  14129. }
  14130. asDWORD asCExprValue::GetConstantDW()
  14131. {
  14132. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14133. return dwordValue;
  14134. }
  14135. asWORD asCExprValue::GetConstantW()
  14136. {
  14137. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  14138. return wordValue;
  14139. }
  14140. asBYTE asCExprValue::GetConstantB()
  14141. {
  14142. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  14143. return byteValue;
  14144. }
  14145. float asCExprValue::GetConstantF()
  14146. {
  14147. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14148. return floatValue;
  14149. }
  14150. double asCExprValue::GetConstantD()
  14151. {
  14152. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14153. return doubleValue;
  14154. }
  14155. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  14156. {
  14157. Set(dt);
  14158. isConstant = true;
  14159. // This code is necessary to guarantee that the code
  14160. // works on both big endian and little endian CPUs.
  14161. if (dataType.GetSizeInMemoryBytes() == 1)
  14162. byteValue = (asBYTE)qw;
  14163. if (dataType.GetSizeInMemoryBytes() == 2)
  14164. wordValue = (asWORD)qw;
  14165. if (dataType.GetSizeInMemoryBytes() == 4)
  14166. dwordValue = (asDWORD)qw;
  14167. else
  14168. qwordValue = qw;
  14169. }
  14170. asQWORD asCExprValue::GetConstantData()
  14171. {
  14172. asQWORD qw = 0;
  14173. // This code is necessary to guarantee that the code
  14174. // works on both big endian and little endian CPUs.
  14175. if (dataType.GetSizeInMemoryBytes() == 1)
  14176. qw = byteValue;
  14177. if (dataType.GetSizeInMemoryBytes() == 2)
  14178. qw = wordValue;
  14179. if (dataType.GetSizeInMemoryBytes() == 4)
  14180. qw = dwordValue;
  14181. else
  14182. qw = qwordValue;
  14183. return qw;
  14184. }
  14185. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  14186. {
  14187. // This is used for when the expression evaluates to a
  14188. // function, but it is not yet known exactly which. The
  14189. // owner expression will hold the name of the function
  14190. // to determine the exact function when the signature is
  14191. // known.
  14192. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  14193. isConstant = true;
  14194. isExplicitHandle = false;
  14195. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  14196. isLValue = false;
  14197. }
  14198. bool asCExprValue::IsUndefinedFuncHandle() const
  14199. {
  14200. if (isConstant == false) return false;
  14201. if (qwordValue == 0) return false;
  14202. if (isLValue) return false;
  14203. if (dataType.GetTypeInfo() == 0) return false;
  14204. if (dataType.GetTypeInfo()->name != "$func") return false;
  14205. if (dataType.IsFuncdef()) return false;
  14206. return true;
  14207. }
  14208. void asCExprValue::SetNullConstant()
  14209. {
  14210. Set(asCDataType::CreateNullHandle());
  14211. isConstant = true;
  14212. isExplicitHandle = false;
  14213. qwordValue = 0;
  14214. isLValue = false;
  14215. }
  14216. bool asCExprValue::IsNullConstant() const
  14217. {
  14218. // We can't check the actual object type, because the null constant may have been cast to another type
  14219. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  14220. return true;
  14221. return false;
  14222. }
  14223. void asCExprValue::SetVoid()
  14224. {
  14225. Set(asCDataType::CreatePrimitive(ttVoid, false));
  14226. isLValue = false;
  14227. isConstant = true;
  14228. }
  14229. bool asCExprValue::IsVoid() const
  14230. {
  14231. if (dataType.GetTokenType() == ttVoid)
  14232. return true;
  14233. return false;
  14234. }
  14235. void asCExprValue::SetDummy()
  14236. {
  14237. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  14238. }
  14239. ////////////////////////////////////////////////////////////////////////////////////////////////
  14240. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  14241. {
  14242. property_arg = 0;
  14243. Clear();
  14244. }
  14245. asCExprContext::~asCExprContext()
  14246. {
  14247. if (property_arg)
  14248. asDELETE(property_arg, asCExprContext);
  14249. }
  14250. void asCExprContext::Clear()
  14251. {
  14252. bc.ClearAll();
  14253. type.Set(asCDataType());
  14254. deferredParams.SetLength(0);
  14255. if (property_arg)
  14256. asDELETE(property_arg, asCExprContext);
  14257. property_arg = 0;
  14258. exprNode = 0;
  14259. origExpr = 0;
  14260. property_get = 0;
  14261. property_set = 0;
  14262. property_const = false;
  14263. property_handle = false;
  14264. property_ref = false;
  14265. methodName = "";
  14266. enumValue = "";
  14267. symbolNamespace = 0;
  14268. isVoidExpression = false;
  14269. isCleanArg = false;
  14270. isAnonymousInitList = false;
  14271. origCode = 0;
  14272. }
  14273. bool asCExprContext::IsClassMethod() const
  14274. {
  14275. if (type.dataType.GetTypeInfo() == 0) return false;
  14276. if (methodName == "") return false;
  14277. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14278. if (isAnonymousInitList) return false;
  14279. return true;
  14280. }
  14281. bool asCExprContext::IsGlobalFunc() const
  14282. {
  14283. if (type.dataType.GetTypeInfo() == 0) return false;
  14284. if (methodName == "") return false;
  14285. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14286. if (isAnonymousInitList) return false;
  14287. return true;
  14288. }
  14289. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  14290. {
  14291. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  14292. asASSERT(bc.GetLastInstr() == -1);
  14293. Clear();
  14294. type.SetUndefinedFuncHandle(bc.GetEngine());
  14295. exprNode = funcDecl;
  14296. }
  14297. bool asCExprContext::IsLambda() const
  14298. {
  14299. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  14300. return true;
  14301. return false;
  14302. }
  14303. void asCExprContext::SetVoidExpression()
  14304. {
  14305. Clear();
  14306. type.SetVoid();
  14307. isVoidExpression = true;
  14308. }
  14309. bool asCExprContext::IsVoidExpression() const
  14310. {
  14311. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  14312. return true;
  14313. return false;
  14314. }
  14315. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script)
  14316. {
  14317. Clear();
  14318. exprNode = initList;
  14319. origCode = script;
  14320. isAnonymousInitList = true;
  14321. }
  14322. bool asCExprContext::IsAnonymousInitList() const
  14323. {
  14324. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  14325. return true;
  14326. return false;
  14327. }
  14328. void asCExprContext::Copy(asCExprContext *other)
  14329. {
  14330. type = other->type;
  14331. property_get = other->property_get;
  14332. property_set = other->property_set;
  14333. property_const = other->property_const;
  14334. property_handle = other->property_handle;
  14335. property_ref = other->property_ref;
  14336. property_arg = other->property_arg;
  14337. exprNode = other->exprNode;
  14338. methodName = other->methodName;
  14339. enumValue = other->enumValue;
  14340. isVoidExpression = other->isVoidExpression;
  14341. isCleanArg = other->isCleanArg;
  14342. isAnonymousInitList = other->isAnonymousInitList;
  14343. origCode = other->origCode;
  14344. // Do not copy the origExpr member
  14345. }
  14346. void asCExprContext::Merge(asCExprContext *after)
  14347. {
  14348. // Overwrite properties with the expression that comes after
  14349. Copy(after);
  14350. // Clean the properties in 'after' that have now moved into
  14351. // this structure so they are not cleaned up accidentally
  14352. after->property_arg = 0;
  14353. }
  14354. END_AS_NAMESPACE
  14355. #endif // AS_NO_COMPILER