as_compiler.cpp 510 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2019 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Oorni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() 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. }
  82. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  83. {
  84. this->builder = in_builder;
  85. this->engine = in_builder->engine;
  86. this->script = in_script;
  87. this->outFunc = in_outFunc;
  88. hasCompileErrors = false;
  89. m_isConstructor = false;
  90. m_isConstructorCalled = false;
  91. m_classDecl = 0;
  92. m_globalVar = 0;
  93. nextLabel = 0;
  94. breakLabels.SetLength(0);
  95. continueLabels.SetLength(0);
  96. numLambdas = 0;
  97. byteCode.ClearAll();
  98. }
  99. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  100. {
  101. Reset(in_builder, in_script, in_outFunc);
  102. m_classDecl = in_classDecl;
  103. // Insert a JitEntry at the start of the function for JIT compilers
  104. byteCode.InstrPTR(asBC_JitEntry, 0);
  105. // Add a variable scope that might be needed to declare dummy variables
  106. // in case the member initialization refers to undefined symbols.
  107. AddVariableScope();
  108. // Initialize the class members that have no explicit expression first. This will allow the
  109. // base class' constructor to access these members without worry they will be uninitialized.
  110. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  111. CompileMemberInitialization(&byteCode, true);
  112. // If the class is derived from another, then the base class' default constructor must be called
  113. if( outFunc->objectType->derivedFrom )
  114. {
  115. // Make sure the base class really has a default constructor
  116. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  117. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  118. // Call the base class' default constructor
  119. byteCode.InstrSHORT(asBC_PSF, 0);
  120. byteCode.Instr(asBC_RDSPtr);
  121. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  122. }
  123. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  124. // to access the base class members without worry they will be uninitialized
  125. CompileMemberInitialization(&byteCode, false);
  126. byteCode.OptimizeLocally(tempVariableOffsets);
  127. // If there are compile errors, there is no reason to build the final code
  128. if( hasCompileErrors )
  129. return -1;
  130. // Pop the object pointer from the stack
  131. byteCode.Ret(AS_PTR_SIZE);
  132. // Count total variable size
  133. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  134. outFunc->scriptData->variableSpace = varSize;
  135. FinalizeFunction();
  136. #ifdef AS_DEBUG
  137. // DEBUG: output byte code
  138. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  139. #endif
  140. return 0;
  141. }
  142. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  143. {
  144. Reset(in_builder, in_script, in_outFunc);
  145. // Insert a JitEntry at the start of the function for JIT compilers
  146. byteCode.InstrPTR(asBC_JitEntry, 0);
  147. // Find the corresponding constructor
  148. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  149. int constructor = 0;
  150. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  151. {
  152. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  153. {
  154. constructor = dt.GetBehaviour()->constructors[n];
  155. break;
  156. }
  157. }
  158. // Allocate the class and instantiate it with the constructor
  159. int varOffset = AllocateVariable(dt, true);
  160. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  161. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  162. // Copy all arguments to the top of the stack
  163. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  164. int offset = (int)outFunc->GetSpaceNeededForArguments();
  165. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  166. {
  167. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  168. outFunc->parameterTypes[a].IsReference() )
  169. {
  170. offset -= AS_PTR_SIZE;
  171. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  172. }
  173. else
  174. {
  175. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  176. {
  177. offset -= 2;
  178. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  179. }
  180. else
  181. {
  182. offset -= 1;
  183. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  184. }
  185. }
  186. }
  187. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  188. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  189. // Return a handle to the newly created object
  190. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  191. byteCode.Ret(argDwords);
  192. FinalizeFunction();
  193. // Tell the virtual machine not to clean up parameters on exception
  194. outFunc->dontCleanUpOnException = true;
  195. /*
  196. #ifdef AS_DEBUG
  197. // DEBUG: output byte code
  198. asCString args;
  199. args.Format("%d", outFunc->parameterTypes.GetLength());
  200. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  201. #endif
  202. */
  203. return 0;
  204. }
  205. void asCCompiler::FinalizeFunction()
  206. {
  207. TimeIt("asCCompiler::FinalizeFunction");
  208. asASSERT( outFunc->scriptData );
  209. asUINT n;
  210. // Finalize the bytecode
  211. byteCode.Finalize(tempVariableOffsets);
  212. // extract the try/catch info before object variable info, as
  213. // some variable info is not needed if there are no try/catch blocks
  214. byteCode.ExtractTryCatchInfo(outFunc);
  215. byteCode.ExtractObjectVariableInfo(outFunc);
  216. // Compile the list of object variables for the exception handler
  217. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  218. for( n = 0; n < variableAllocations.GetLength(); n++ )
  219. {
  220. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  221. {
  222. if( variableIsOnHeap[n] )
  223. {
  224. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  225. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  226. }
  227. }
  228. }
  229. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  230. for( n = 0; n < variableAllocations.GetLength(); n++ )
  231. {
  232. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  233. {
  234. if( !variableIsOnHeap[n] )
  235. {
  236. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  237. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  238. }
  239. }
  240. }
  241. // Copy byte code to the function
  242. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  243. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  244. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  245. outFunc->AddReferences();
  246. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  247. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  248. // Extract the script section indexes too if there are any entries that are different from the function's script section
  249. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  250. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  251. {
  252. if( byteCode.sectionIdxs[n] != lastIdx )
  253. {
  254. lastIdx = byteCode.sectionIdxs[n];
  255. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  256. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  257. }
  258. }
  259. }
  260. // internal
  261. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  262. {
  263. int stackPos = 0;
  264. if( outFunc->objectType )
  265. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  266. // Add the first variable scope, which the parameters and
  267. // variables declared in the outermost statement block is
  268. // part of.
  269. AddVariableScope();
  270. bool isDestructor = false;
  271. asCDataType returnType;
  272. // Examine return type
  273. returnType = outFunc->returnType;
  274. // Check if this is a constructor or destructor
  275. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  276. {
  277. if( outFunc->name[0] == '~' )
  278. isDestructor = true;
  279. else if( outFunc->objectType->name == outFunc->name )
  280. m_isConstructor = true;
  281. }
  282. // Is the return type allowed?
  283. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  284. !returnType.CanBeInstantiated() )
  285. {
  286. // TODO: Hasn't this been validated by the builder already?
  287. asCString str;
  288. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  289. Error(str, func);
  290. }
  291. // If the return type is a value type returned by value the address of the
  292. // location where the value will be stored is pushed on the stack before
  293. // the arguments
  294. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  295. stackPos -= AS_PTR_SIZE;
  296. asCVariableScope vs(0);
  297. // Declare parameters
  298. asUINT n;
  299. for( n = 0; n < parameterNames.GetLength(); n++ )
  300. {
  301. // Get the parameter type
  302. asCDataType &type = outFunc->parameterTypes[n];
  303. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  304. // Is the data type allowed?
  305. // TODO: Hasn't this been validated by the builder already?
  306. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  307. (!type.IsReference() && !type.CanBeInstantiated()) )
  308. {
  309. asCString parm = type.Format(outFunc->nameSpace);
  310. if( inoutFlag == asTM_INREF )
  311. parm += "in";
  312. else if( inoutFlag == asTM_OUTREF )
  313. parm += "out";
  314. asCString str;
  315. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  316. Error(str, func);
  317. }
  318. // If the parameter has a name then declare it as variable
  319. if( parameterNames[n] != "" )
  320. {
  321. asCString &name = parameterNames[n];
  322. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  323. {
  324. // TODO: It might be an out-of-memory too
  325. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  326. }
  327. // Add marker for variable declaration
  328. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  329. outFunc->AddVariable(name, type, stackPos);
  330. }
  331. else
  332. vs.DeclareVariable("", type, stackPos, true);
  333. // Move to next parameter
  334. stackPos -= type.GetSizeOnStackDWords();
  335. }
  336. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  337. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  338. variables->DeclareVariable("return", returnType, stackPos, true);
  339. return stackPos;
  340. }
  341. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  342. {
  343. asASSERT( m_classDecl );
  344. // Initialize each member in the order they were declared
  345. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  346. {
  347. asCObjectProperty *prop = outFunc->objectType->properties[n];
  348. // Check if the property has an initialization expression
  349. asCScriptNode *declNode = 0;
  350. asCScriptNode *initNode = 0;
  351. asCScriptCode *initScript = 0;
  352. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  353. {
  354. if( m_classDecl->propInits[m].name == prop->name )
  355. {
  356. declNode = m_classDecl->propInits[m].declNode;
  357. initNode = m_classDecl->propInits[m].initNode;
  358. initScript = m_classDecl->propInits[m].file;
  359. break;
  360. }
  361. }
  362. // If declNode is null, the property was inherited in which case
  363. // it was already initialized by the base class' constructor
  364. if( declNode )
  365. {
  366. if( initNode )
  367. {
  368. if( onlyDefaults )
  369. continue;
  370. #ifdef AS_NO_MEMBER_INIT
  371. // Give an error as the initialization in the declaration has been disabled
  372. asCScriptCode *origScript = script;
  373. script = initScript;
  374. Error("Initialization of members in declaration is not supported", initNode);
  375. script = origScript;
  376. // Clear the initialization node
  377. initNode = 0;
  378. initScript = script;
  379. #else
  380. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  381. asCParser parser(builder);
  382. int r = parser.ParseVarInit(initScript, initNode);
  383. if( r < 0 )
  384. continue;
  385. initNode = parser.GetScriptNode();
  386. #endif
  387. }
  388. else
  389. {
  390. if( !onlyDefaults )
  391. continue;
  392. }
  393. #ifdef AS_NO_MEMBER_INIT
  394. // The initialization will be done in the asCScriptObject constructor, so
  395. // here we should just validate that the member has a default constructor
  396. if( prop->type.IsObject() &&
  397. !prop->type.IsObjectHandle() &&
  398. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  399. prop->type.GetBehaviour()->factory == 0) ||
  400. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  401. prop->type.GetBehaviour()->construct == 0 &&
  402. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  403. {
  404. // Class has no default factory/constructor.
  405. asCString str;
  406. // TODO: funcdef: asCDataType should have a GetTypeName()
  407. if( prop->type.GetFuncDef() )
  408. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  409. else
  410. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  411. Error(str, declNode);
  412. }
  413. #else
  414. // Temporarily set the script that is being compiled to where the member initialization is declared.
  415. // The script can be different when including mixin classes from a different script section
  416. asCScriptCode *origScript = script;
  417. script = initScript;
  418. // Add a line instruction with the position of the declaration
  419. LineInstr(bc, declNode->tokenPos);
  420. // Compile the initialization
  421. asQWORD constantValue;
  422. asCByteCode bcInit(engine);
  423. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  424. bcInit.OptimizeLocally(tempVariableOffsets);
  425. bc->AddCode(&bcInit);
  426. script = origScript;
  427. #endif
  428. }
  429. }
  430. }
  431. // Entry
  432. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  433. {
  434. TimeIt("asCCompiler::CompileFunction");
  435. Reset(in_builder, in_script, in_outFunc);
  436. int buildErrors = builder->numErrors;
  437. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  438. //--------------------------------------------
  439. // Compile the statement block
  440. if( m_isConstructor )
  441. m_classDecl = in_classDecl;
  442. // We need to parse the statement block now
  443. asCScriptNode *blockBegin;
  444. // If the function signature was implicit, e.g. virtual property accessor or
  445. // lambda function, then the received node already is the statement block
  446. if( in_func->nodeType != snStatementBlock )
  447. blockBegin = in_func->lastChild;
  448. else
  449. blockBegin = in_func;
  450. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  451. // 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
  452. asCParser parser(builder);
  453. int r = parser.ParseStatementBlock(script, blockBegin);
  454. if( r < 0 ) return -1;
  455. asCScriptNode *block = parser.GetScriptNode();
  456. // Reserve a label for the cleanup code
  457. nextLabel++;
  458. bool hasReturn;
  459. asCByteCode bc(engine);
  460. LineInstr(&bc, blockBegin->tokenPos);
  461. CompileStatementBlock(block, false, &hasReturn, &bc);
  462. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  463. // Make sure there is a return in all paths (if not return type is void)
  464. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  465. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  466. {
  467. if( hasReturn == false )
  468. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  469. }
  470. //------------------------------------------------
  471. // Concatenate the bytecode
  472. // Insert a JitEntry at the start of the function for JIT compilers
  473. byteCode.InstrPTR(asBC_JitEntry, 0);
  474. if( outFunc->objectType )
  475. {
  476. if( m_isConstructor )
  477. {
  478. if( outFunc->objectType->derivedFrom )
  479. {
  480. // Call the base class' default constructor unless called manually in the code
  481. if( !m_isConstructorCalled )
  482. {
  483. if( outFunc->objectType->derivedFrom->beh.construct )
  484. {
  485. // Initialize members without explicit expression first
  486. CompileMemberInitialization(&byteCode, true);
  487. // Call base class' constructor
  488. asCByteCode tmpBC(engine);
  489. tmpBC.InstrSHORT(asBC_PSF, 0);
  490. tmpBC.Instr(asBC_RDSPtr);
  491. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  492. tmpBC.OptimizeLocally(tempVariableOffsets);
  493. byteCode.AddCode(&tmpBC);
  494. // Add the initialization of the members with explicit expressions
  495. CompileMemberInitialization(&byteCode, false);
  496. }
  497. else
  498. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  499. }
  500. else
  501. {
  502. // Only initialize members that don't have an explicit expression
  503. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  504. CompileMemberInitialization(&byteCode, true);
  505. }
  506. }
  507. else
  508. {
  509. // Add the initialization of the members
  510. CompileMemberInitialization(&byteCode, true);
  511. CompileMemberInitialization(&byteCode, false);
  512. }
  513. }
  514. }
  515. // Add the code for the statement block
  516. byteCode.AddCode(&bc);
  517. // Count total variable size
  518. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  519. outFunc->scriptData->variableSpace = varSize;
  520. // Deallocate all local variables
  521. int n;
  522. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  523. {
  524. sVariable *v = variables->variables[n];
  525. if( v->stackOffset > 0 )
  526. {
  527. // Call variables destructors
  528. if( v->name != "return" && v->name != "return address" )
  529. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  530. DeallocateVariable(v->stackOffset);
  531. }
  532. }
  533. // This is the label that return statements jump to
  534. // in order to exit the function
  535. byteCode.Label(0);
  536. // Call destructors for function parameters
  537. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  538. {
  539. sVariable *v = variables->variables[n];
  540. if( v->stackOffset <= 0 )
  541. {
  542. // Call variable destructors here, for variables not yet destroyed
  543. if( v->name != "return" && v->name != "return address" )
  544. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  545. }
  546. // Do not deallocate parameters
  547. }
  548. // Check if the number of labels in the functions isn't too many to be handled
  549. if( nextLabel >= (1<<15) )
  550. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  551. // If there are compile errors, there is no reason to build the final code
  552. if( hasCompileErrors || builder->numErrors != buildErrors )
  553. return -1;
  554. // At this point there should be no variables allocated
  555. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  556. // Remove the variable scope
  557. RemoveVariableScope();
  558. byteCode.Ret(-stackPos);
  559. FinalizeFunction();
  560. #ifdef AS_DEBUG
  561. // DEBUG: output byte code
  562. if( outFunc->objectType )
  563. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  564. else
  565. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  566. #endif
  567. return 0;
  568. }
  569. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  570. {
  571. if( !type.IsObject() )
  572. return 0;
  573. // CallCopyConstructor should not be called for object handles.
  574. asASSERT( !type.IsObjectHandle() );
  575. asCArray<asCExprContext*> args;
  576. args.PushLast(arg);
  577. // The reference parameter must be pushed on the stack
  578. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  579. // Since we're calling the copy constructor, we have to trust the function to not do
  580. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  581. // copies of the argument in order to guarantee safety.
  582. if( type.GetTypeInfo()->flags & asOBJ_REF )
  583. {
  584. asCExprContext ctx(engine);
  585. int func = 0;
  586. asSTypeBehaviour *beh = type.GetBehaviour();
  587. if( beh ) func = beh->copyfactory;
  588. if( func > 0 )
  589. {
  590. if( !isGlobalVar )
  591. {
  592. // Call factory and store the handle in the given variable
  593. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  594. // Pop the reference left by the function call
  595. ctx.bc.Instr(asBC_PopPtr);
  596. }
  597. else
  598. {
  599. // Call factory
  600. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  601. // Store the returned handle in the global variable
  602. ctx.bc.Instr(asBC_RDSPtr);
  603. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  604. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  605. ctx.bc.Instr(asBC_PopPtr);
  606. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  607. }
  608. bc->AddCode(&ctx.bc);
  609. return 0;
  610. }
  611. }
  612. else
  613. {
  614. asSTypeBehaviour *beh = type.GetBehaviour();
  615. int func = beh ? beh->copyconstruct : 0;
  616. if( func > 0 )
  617. {
  618. // Push the address where the object will be stored on the stack, before the argument
  619. // TODO: When the context is serializable this probably has to be changed, since this
  620. // pointer can remain on the stack while the context is suspended. There is no
  621. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  622. asCByteCode tmp(engine);
  623. if( isGlobalVar )
  624. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  625. else if( isObjectOnHeap )
  626. tmp.InstrSHORT(asBC_PSF, (short)offset);
  627. tmp.AddCode(bc);
  628. bc->AddCode(&tmp);
  629. // When the object is allocated on the stack the object pointer
  630. // must be pushed on the stack after the arguments
  631. if( !isObjectOnHeap )
  632. {
  633. asASSERT( !isGlobalVar );
  634. bc->InstrSHORT(asBC_PSF, (short)offset);
  635. if( derefDest )
  636. {
  637. // The variable is a reference to the real location, so we need to dereference it
  638. bc->Instr(asBC_RDSPtr);
  639. }
  640. }
  641. asCExprContext ctx(engine);
  642. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  643. bc->AddCode(&ctx.bc);
  644. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  645. // Mark the object as initialized
  646. if( !isObjectOnHeap )
  647. bc->ObjInfo(offset, asOBJ_INIT);
  648. return 0;
  649. }
  650. }
  651. // Class has no copy constructor/factory.
  652. asCString str;
  653. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  654. Error(str, node);
  655. return -1;
  656. }
  657. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  658. {
  659. if( !type.IsObject() || type.IsObjectHandle() )
  660. return 0;
  661. if( type.GetTypeInfo()->flags & asOBJ_REF )
  662. {
  663. asCExprContext ctx(engine);
  664. ctx.exprNode = node;
  665. int func = 0;
  666. asSTypeBehaviour *beh = type.GetBehaviour();
  667. if( beh )
  668. {
  669. func = beh->factory;
  670. // If no trivial default factory is found, look for a factory where all params have default args
  671. if( func == 0 )
  672. {
  673. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  674. {
  675. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  676. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  677. f->defaultArgs[0] != 0 )
  678. {
  679. func = beh->factories[n];
  680. break;
  681. }
  682. }
  683. }
  684. }
  685. if( func > 0 )
  686. {
  687. asCArray<asCExprContext *> args;
  688. asCScriptFunction *f = engine->scriptFunctions[func];
  689. if( f->parameterTypes.GetLength() )
  690. {
  691. // Add the default values for arguments not explicitly supplied
  692. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  693. PrepareFunctionCall(func, &ctx.bc, args);
  694. MoveArgsToStack(func, &ctx.bc, args, false);
  695. }
  696. if( isVarGlobOrMem == 0 )
  697. {
  698. // Call factory and store the handle in the given variable
  699. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  700. // Pop the reference left by the function call
  701. ctx.bc.Instr(asBC_PopPtr);
  702. }
  703. else
  704. {
  705. // Call factory
  706. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  707. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  708. // instead of first storing it in a local variable and then copying it to the
  709. // destination.
  710. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  711. {
  712. // Only dereference the variable if not a scoped type
  713. ctx.bc.Instr(asBC_RDSPtr);
  714. }
  715. if( isVarGlobOrMem == 1 )
  716. {
  717. // Store the returned handle in the global variable
  718. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  719. }
  720. else
  721. {
  722. // Store the returned handle in the class member
  723. ctx.bc.InstrSHORT(asBC_PSF, 0);
  724. ctx.bc.Instr(asBC_RDSPtr);
  725. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  726. }
  727. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  728. {
  729. // For scoped typed we must move the reference from the local
  730. // variable rather than copy it as there is no AddRef behaviour
  731. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  732. // Clear the local variable so the reference isn't released
  733. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  734. }
  735. else
  736. {
  737. if( type.IsFuncdef() )
  738. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  739. else
  740. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  741. }
  742. ctx.bc.Instr(asBC_PopPtr);
  743. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  744. }
  745. bc->AddCode(&ctx.bc);
  746. // Cleanup
  747. for( asUINT n = 0; n < args.GetLength(); n++ )
  748. if( args[n] )
  749. {
  750. asDELETE(args[n], asCExprContext);
  751. }
  752. return 0;
  753. }
  754. }
  755. else
  756. {
  757. asCExprContext ctx(engine);
  758. ctx.exprNode = node;
  759. asSTypeBehaviour *beh = type.GetBehaviour();
  760. int func = 0;
  761. if( beh )
  762. {
  763. func = beh->construct;
  764. // If no trivial default constructor is found, look for a constructor where all params have default args
  765. if( func == 0 )
  766. {
  767. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  768. {
  769. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  770. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  771. f->defaultArgs[0] != 0 )
  772. {
  773. func = beh->constructors[n];
  774. break;
  775. }
  776. }
  777. }
  778. }
  779. // Allocate and initialize with the default constructor
  780. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  781. {
  782. asCArray<asCExprContext *> args;
  783. asCScriptFunction *f = engine->scriptFunctions[func];
  784. if( f && f->parameterTypes.GetLength() )
  785. {
  786. // Add the default values for arguments not explicitly supplied
  787. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  788. PrepareFunctionCall(func, &ctx.bc, args);
  789. MoveArgsToStack(func, &ctx.bc, args, false);
  790. }
  791. if( !isObjectOnHeap )
  792. {
  793. if( isVarGlobOrMem == 0 )
  794. {
  795. // There is nothing to do if there is no function,
  796. // as the memory is already allocated on the stack
  797. if( func )
  798. {
  799. // Call the constructor as a normal function
  800. bc->InstrSHORT(asBC_PSF, (short)offset);
  801. if( derefDest )
  802. bc->Instr(asBC_RDSPtr);
  803. asCExprContext ctxCall(engine);
  804. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  805. bc->AddCode(&ctxCall.bc);
  806. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  807. // Mark the object as initialized
  808. bc->ObjInfo(offset, asOBJ_INIT);
  809. }
  810. }
  811. else if( isVarGlobOrMem == 2 )
  812. {
  813. // Only POD types can be allocated inline in script classes
  814. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  815. if( func )
  816. {
  817. // Call the constructor as a normal function
  818. bc->InstrSHORT(asBC_PSF, 0);
  819. bc->Instr(asBC_RDSPtr);
  820. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  821. asCExprContext ctxCall(engine);
  822. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  823. bc->AddCode(&ctxCall.bc);
  824. }
  825. }
  826. else
  827. {
  828. asASSERT( false );
  829. }
  830. }
  831. else
  832. {
  833. if( isVarGlobOrMem == 0 )
  834. bc->InstrSHORT(asBC_PSF, (short)offset);
  835. else if( isVarGlobOrMem == 1 )
  836. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  837. else
  838. {
  839. bc->InstrSHORT(asBC_PSF, 0);
  840. bc->Instr(asBC_RDSPtr);
  841. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  842. }
  843. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  844. {
  845. asCScriptFunction *descr = engine->scriptFunctions[func];
  846. asASSERT( descr->funcType == asFUNC_SCRIPT );
  847. // Find the id of the real constructor and not the generated stub
  848. asUINT id = 0;
  849. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  850. while( funcBc )
  851. {
  852. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  853. {
  854. id = asBC_INTARG(funcBc);
  855. break;
  856. }
  857. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  858. }
  859. asASSERT( id );
  860. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  861. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  862. }
  863. else
  864. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  865. }
  866. // Cleanup
  867. for( asUINT n = 0; n < args.GetLength(); n++ )
  868. if( args[n] )
  869. {
  870. asDELETE(args[n], asCExprContext);
  871. }
  872. return 0;
  873. }
  874. }
  875. // Class has no default factory/constructor.
  876. asCString str;
  877. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  878. Error(str, node);
  879. return -1;
  880. }
  881. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  882. {
  883. if( !type.IsReference() )
  884. {
  885. // Call destructor for the data type
  886. if( type.IsObject() || type.IsFuncdef() )
  887. {
  888. // The null pointer doesn't need to be destroyed
  889. if( type.IsNullHandle() )
  890. return;
  891. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  892. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  893. return;
  894. if( isObjectOnHeap || type.IsObjectHandle() )
  895. {
  896. // Free the memory
  897. if (type.IsFuncdef())
  898. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  899. else
  900. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  901. }
  902. else
  903. {
  904. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  905. if( type.GetBehaviour()->destruct )
  906. {
  907. // Call the destructor as a regular function
  908. asCExprContext ctx(engine);
  909. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  910. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  911. ctx.bc.OptimizeLocally(tempVariableOffsets);
  912. bc->AddCode(&ctx.bc);
  913. }
  914. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  915. // Mark the object as destroyed
  916. bc->ObjInfo(offset, asOBJ_UNINIT);
  917. }
  918. }
  919. }
  920. }
  921. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  922. {
  923. int r, c;
  924. script->ConvertPosToRowCol(pos, &r, &c);
  925. bc->Line(r, c, script->idx);
  926. }
  927. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  928. {
  929. *hasReturn = false;
  930. bool isFinished = false;
  931. bool hasUnreachableCode = false;
  932. bool hasReturnBefore = false;
  933. if( ownVariableScope )
  934. {
  935. bc->Block(true);
  936. AddVariableScope();
  937. }
  938. asCScriptNode *node = block->firstChild;
  939. while( node )
  940. {
  941. #ifdef AS_DEBUG
  942. // Keep the current line in a variable so it will be easier
  943. // to determine where in a script an assert is occurring.
  944. int currentLine = 0;
  945. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  946. #endif
  947. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  948. {
  949. // Empty statements don't count
  950. if( node->nodeType != snExpressionStatement || node->firstChild )
  951. {
  952. hasUnreachableCode = true;
  953. Warning(TXT_UNREACHABLE_CODE, node);
  954. }
  955. if( *hasReturn )
  956. hasReturnBefore = true;
  957. }
  958. if( node->nodeType == snBreak || node->nodeType == snContinue )
  959. isFinished = true;
  960. asCByteCode statement(engine);
  961. if( node->nodeType == snDeclaration )
  962. CompileDeclaration(node, &statement);
  963. else
  964. CompileStatement(node, hasReturn, &statement);
  965. // Ignore missing returns in unreachable code paths
  966. if( !(*hasReturn) && hasReturnBefore )
  967. *hasReturn = true;
  968. LineInstr(bc, node->tokenPos);
  969. bc->AddCode(&statement);
  970. if( !hasCompileErrors )
  971. {
  972. asASSERT( tempVariables.GetLength() == 0 );
  973. asASSERT( reservedVariables.GetLength() == 0 );
  974. }
  975. node = node->next;
  976. }
  977. if( ownVariableScope )
  978. {
  979. // Deallocate variables in this block, in reverse order
  980. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  981. {
  982. sVariable *v = variables->variables[n];
  983. // Call variable destructors here, for variables not yet destroyed
  984. // If the block is terminated with a break, continue, or
  985. // return the variables are already destroyed
  986. if( !isFinished && !*hasReturn )
  987. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  988. // Don't deallocate function parameters
  989. if( v->stackOffset > 0 )
  990. DeallocateVariable(v->stackOffset);
  991. }
  992. RemoveVariableScope();
  993. bc->Block(false);
  994. }
  995. }
  996. // Entry
  997. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  998. {
  999. Reset(in_builder, in_script, in_outFunc);
  1000. m_globalVar = in_gvar;
  1001. // Add a variable scope (even though variables can't be declared)
  1002. AddVariableScope();
  1003. in_gvar->isPureConstant = false;
  1004. // Parse the initialization nodes
  1005. asCParser parser(builder);
  1006. if (in_node)
  1007. {
  1008. int r = parser.ParseVarInit(in_script, in_node);
  1009. if (r < 0)
  1010. return r;
  1011. in_node = parser.GetScriptNode();
  1012. }
  1013. asCExprContext compiledCtx(engine);
  1014. bool preCompiled = false;
  1015. if (in_gvar->datatype.IsAuto())
  1016. {
  1017. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1018. if (!preCompiled)
  1019. {
  1020. // If it wasn't possible to determine the type from the expression then there
  1021. // is no need to continue with the initialization. The error was already reported
  1022. // in CompileAutoType.
  1023. return -1;
  1024. }
  1025. }
  1026. if( in_gvar->property == 0 )
  1027. {
  1028. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1029. in_gvar->index = in_gvar->property->id;
  1030. }
  1031. // Compile the expression
  1032. asCExprContext ctx(engine);
  1033. asQWORD constantValue = 0;
  1034. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1035. {
  1036. // Should the variable be marked as pure constant?
  1037. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1038. {
  1039. in_gvar->isPureConstant = true;
  1040. in_gvar->constantValue = constantValue;
  1041. }
  1042. }
  1043. // Concatenate the bytecode
  1044. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1045. // Add information on the line number for the global variable
  1046. size_t pos = 0;
  1047. if( in_gvar->declaredAtNode )
  1048. pos = in_gvar->declaredAtNode->tokenPos;
  1049. else if( in_gvar->initializationNode )
  1050. pos = in_gvar->initializationNode->tokenPos;
  1051. LineInstr(&byteCode, pos);
  1052. // Reserve space for all local variables
  1053. outFunc->scriptData->variableSpace = varSize;
  1054. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1055. byteCode.AddCode(&ctx.bc);
  1056. // Deallocate variables in this block, in reverse order
  1057. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1058. {
  1059. sVariable *v = variables->variables[n];
  1060. // Call variable destructors here, for variables not yet destroyed
  1061. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1062. DeallocateVariable(v->stackOffset);
  1063. }
  1064. if( hasCompileErrors ) return -1;
  1065. // At this point there should be no variables allocated
  1066. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1067. // Remove the variable scope again
  1068. RemoveVariableScope();
  1069. byteCode.Ret(0);
  1070. FinalizeFunction();
  1071. #ifdef AS_DEBUG
  1072. // DEBUG: output byte code
  1073. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1074. #endif
  1075. return 0;
  1076. }
  1077. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1078. {
  1079. // Don't do anything if this is not a deferred global function
  1080. if( !ctx->IsGlobalFunc() )
  1081. return;
  1082. // Determine the namespace
  1083. asSNameSpace *ns = 0;
  1084. asCString name = "";
  1085. int pos = ctx->methodName.FindLast("::");
  1086. if( pos >= 0 )
  1087. {
  1088. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1089. // Cut off the ::
  1090. if( nsName.GetLength() > 2 )
  1091. nsName.SetLength(nsName.GetLength()-2);
  1092. ns = DetermineNameSpace(nsName);
  1093. name = ctx->methodName.SubString(pos+2);
  1094. }
  1095. else
  1096. {
  1097. DetermineNameSpace("");
  1098. name = ctx->methodName;
  1099. }
  1100. asCArray<int> funcs;
  1101. if( ns )
  1102. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1103. // CompileVariableAccess should guarantee that at least one function is exists
  1104. asASSERT( funcs.GetLength() > 0 );
  1105. if( funcs.GetLength() > 1 )
  1106. {
  1107. asCString str;
  1108. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1109. Error(str, node);
  1110. // Fall through so the compiler can continue as if only one function was matching
  1111. }
  1112. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1113. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1114. outFunc->IsShared() )
  1115. {
  1116. asCString msg;
  1117. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1118. Error(msg, node);
  1119. // Fall through so the compiler can continue anyway
  1120. }
  1121. // Push the function pointer on the stack
  1122. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1123. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1124. ctx->type.dataType.MakeHandle(true);
  1125. ctx->type.isExplicitHandle = true;
  1126. ctx->methodName = "";
  1127. }
  1128. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1129. {
  1130. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1131. // Use copy constructor if available.
  1132. asCObjectType *ot = CastToObjectType(dt.GetTypeInfo());
  1133. if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory))
  1134. {
  1135. PrepareForAssignment(&dt, arg, node, true);
  1136. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1137. if( r < 0 && tempVariables.Exists(offset) )
  1138. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1139. }
  1140. else
  1141. {
  1142. // TODO: Need to reserve variables, as the default constructor may need
  1143. // to allocate temporary variables to compute default args
  1144. // Allocate and construct the temporary object before whatever is already in the bytecode
  1145. asCByteCode tmpBC(engine);
  1146. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1147. if( r < 0 )
  1148. {
  1149. if( tempVariables.Exists(offset) )
  1150. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1151. return;
  1152. }
  1153. tmpBC.AddCode(bc);
  1154. bc->AddCode(&tmpBC);
  1155. // Assign the evaluated expression to the temporary variable
  1156. PrepareForAssignment(&dt, arg, node, true);
  1157. bc->AddCode(&arg->bc);
  1158. // Call the opAssign method to assign the value to the temporary object
  1159. dt.MakeReference(isObjectOnHeap);
  1160. asCExprValue type;
  1161. type.Set(dt);
  1162. type.isTemporary = true;
  1163. type.stackOffset = (short)offset;
  1164. if( dt.IsObjectHandle() )
  1165. type.isExplicitHandle = true;
  1166. bc->InstrSHORT(asBC_PSF, (short)offset);
  1167. if( derefDestination )
  1168. bc->Instr(asBC_RDSPtr);
  1169. r = PerformAssignment(&type, &arg->type, bc, node);
  1170. if( r < 0 )
  1171. {
  1172. if( tempVariables.Exists(offset) )
  1173. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1174. return;
  1175. }
  1176. // Pop the reference that was pushed on the stack if the result is an object
  1177. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1178. bc->Instr(asBC_PopPtr);
  1179. // If the assignment operator returned an object by value it will
  1180. // be in a temporary variable which we need to destroy now
  1181. if( type.isTemporary && type.stackOffset != (short)offset )
  1182. ReleaseTemporaryVariable(type.stackOffset, bc);
  1183. // Release the original value too in case it is a temporary
  1184. ReleaseTemporaryVariable(arg->type, bc);
  1185. }
  1186. }
  1187. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1188. {
  1189. asCDataType param = *paramType;
  1190. if( paramType->GetTokenType() == ttQuestion )
  1191. {
  1192. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1193. DetermineSingleFunc(ctx, node);
  1194. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1195. param = ctx->type.dataType;
  1196. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1197. // Treat the void expression like a null handle when working with var types
  1198. if( ctx->IsVoidExpression() )
  1199. param = asCDataType::CreateNullHandle();
  1200. // If value assign is disabled for reference types, then make
  1201. // sure to always pass the handle to ? parameters
  1202. if( builder->engine->ep.disallowValueAssignForRefType &&
  1203. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1204. {
  1205. param.MakeHandle(true);
  1206. }
  1207. param.MakeReference(paramType->IsReference());
  1208. param.MakeReadOnly(paramType->IsReadOnly());
  1209. }
  1210. else
  1211. param = *paramType;
  1212. asCDataType dt = param;
  1213. // Need to protect arguments by reference
  1214. if( isFunction && dt.IsReference() )
  1215. {
  1216. // Allocate a temporary variable of the same type as the argument
  1217. dt.MakeReference(false);
  1218. int offset;
  1219. if( refType == asTM_INREF )
  1220. {
  1221. ProcessPropertyGetAccessor(ctx, node);
  1222. // Add the type id as hidden arg if the parameter is a ? type
  1223. if( paramType->GetTokenType() == ttQuestion )
  1224. {
  1225. asCByteCode tmpBC(engine);
  1226. // Place the type id on the stack as a hidden parameter
  1227. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1228. // Insert the code before the expression code
  1229. tmpBC.AddCode(&ctx->bc);
  1230. ctx->bc.AddCode(&tmpBC);
  1231. }
  1232. if( dt.IsPrimitive() )
  1233. {
  1234. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1235. // Even if the same variable is passed in another argument as non-const then there is no problem
  1236. IsVariableInitialized(&ctx->type, node);
  1237. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1238. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1239. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1240. ConvertToTempVariable(ctx);
  1241. PushVariableOnStack(ctx, true);
  1242. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1243. }
  1244. else if( ctx->type.dataType.IsNullHandle() )
  1245. {
  1246. // Make sure the argument type can support handles (or is itself a handle)
  1247. if( !dt.SupportHandles() && !dt.IsObjectHandle() )
  1248. {
  1249. asCString str;
  1250. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1251. Error(str, node);
  1252. ctx->type.Set(param);
  1253. return -1;
  1254. }
  1255. // Need to initialize a local temporary variable to
  1256. // represent the null handle when passed as reference
  1257. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1258. ctx->bc.Instr(asBC_PopPtr);
  1259. dt.MakeHandle(true);
  1260. dt.MakeReadOnly(false);
  1261. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1262. // Push the reference to the variable on the stack
  1263. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1264. ctx->type.SetVariable(dt, offset, true);
  1265. ctx->type.isExplicitHandle = true;
  1266. }
  1267. else
  1268. {
  1269. IsVariableInitialized(&ctx->type, node);
  1270. if( !isMakingCopy )
  1271. {
  1272. // For parameters expecting a reference to a handle we need to make sure the argument
  1273. // is really a handle, and not just a reference to the object. Do this check before the
  1274. // implicit conversion so it can be treated correctly.
  1275. if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle())
  1276. {
  1277. // Make a refCopy into a local handle variable
  1278. // Allocate a handle variable
  1279. dt.MakeHandle(true);
  1280. dt.MakeReadOnly(false);
  1281. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1282. // Copy the handle
  1283. Dereference(ctx, true);
  1284. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1285. if (ctx->type.dataType.IsFuncdef())
  1286. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1287. else
  1288. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1289. ctx->bc.Instr(asBC_PopPtr);
  1290. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1291. // Release the original temporary variable
  1292. if( ctx->type.isTemporary )
  1293. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1294. ctx->type.SetVariable(dt, offset, true);
  1295. }
  1296. // Even though the parameter expects a reference, it is only meant to be
  1297. // used as input value and doesn't have to refer to the actual object, so it
  1298. // is OK to do an implicit conversion.
  1299. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1300. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1301. {
  1302. asCString str;
  1303. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1304. Error(str, node);
  1305. ctx->type.Set(param);
  1306. return -1;
  1307. }
  1308. // The compiler must guarantee that the object stays alive during the execution
  1309. // of the function, and it must also guarantee that the value isn't modified by
  1310. // the function.
  1311. // If the argument is a temporary local variable then it is safe to be passed to
  1312. // the function as it is, since the local variable will stay alive, and since it
  1313. // is temporary there is no side effect if the function modifies it.
  1314. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1315. // function, then it is enough that the variable is local to guarantee the lifetime.
  1316. if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) )
  1317. {
  1318. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1319. {
  1320. // Funcdefs only need an extra handle to guarantee the lifetime.
  1321. // If the object is a reference type (except scoped reference types), and the
  1322. // parameter is a const reference, then it is not necessary to make a copy of the
  1323. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1324. // Allocate a handle variable
  1325. dt.MakeHandle(true);
  1326. dt.MakeReadOnly(false);
  1327. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1328. // Copy the handle
  1329. Dereference(ctx, true);
  1330. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1331. if (ctx->type.dataType.IsFuncdef())
  1332. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1333. else
  1334. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1335. ctx->bc.Instr(asBC_PopPtr);
  1336. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1337. // The type should be set to the param type instead of dt to guarantee
  1338. // that the expression keeps the correct type for variable ? args. Otherwise
  1339. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1340. bool isExplicitHandle = ctx->type.isExplicitHandle;
  1341. ctx->type.SetVariable(param, offset, true);
  1342. ctx->type.dataType.MakeHandle(true);
  1343. ctx->type.isExplicitHandle = isExplicitHandle;
  1344. }
  1345. else
  1346. {
  1347. // Make a copy of the object to guarantee that the original isn't modified
  1348. asASSERT(!dt.IsFuncdef());
  1349. // Allocate and initialize a temporary local object
  1350. dt.MakeReadOnly(false);
  1351. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1352. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1353. // Push the object pointer on the stack
  1354. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1355. if( dt.IsObject() && !dt.IsObjectHandle() )
  1356. ctx->bc.Instr(asBC_RDSPtr);
  1357. // Set the resulting type
  1358. ctx->type.Set(dt);
  1359. ctx->type.isTemporary = true;
  1360. ctx->type.stackOffset = short(offset);
  1361. if( dt.IsObjectHandle() )
  1362. ctx->type.isExplicitHandle = true;
  1363. ctx->type.dataType.MakeReference(false);
  1364. if( paramType->IsReadOnly() )
  1365. ctx->type.dataType.MakeReadOnly(true);
  1366. }
  1367. }
  1368. // When calling a function expecting a var arg with a parameter received as reference to handle
  1369. // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
  1370. // not be able to do the correct double dereference to put the reference to the object on the stack.
  1371. if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
  1372. {
  1373. sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
  1374. if (var && var->type.IsReference() && var->type.IsObjectHandle())
  1375. {
  1376. // Copy the handle to local variable
  1377. // Allocate a handle variable
  1378. dt.MakeHandle(true);
  1379. dt.MakeReadOnly(false);
  1380. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1381. // Copy the handle
  1382. Dereference(ctx, true);
  1383. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1384. if (ctx->type.dataType.IsFuncdef())
  1385. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1386. else
  1387. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1388. ctx->bc.Instr(asBC_PopPtr);
  1389. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1390. // The type should be set to the param type instead of dt to guarantee
  1391. // that the expression keeps the correct type for variable ? args. Otherwise
  1392. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1393. ctx->type.SetVariable(param, offset, true);
  1394. }
  1395. }
  1396. }
  1397. else
  1398. {
  1399. // We must guarantee that the address to the value is on the stack
  1400. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1401. !ctx->type.dataType.IsObjectHandle() &&
  1402. ctx->type.dataType.IsReference() )
  1403. Dereference(ctx, true);
  1404. }
  1405. }
  1406. }
  1407. else if( refType == asTM_OUTREF )
  1408. {
  1409. // Add the type id as hidden arg if the parameter is a ? type
  1410. if( paramType->GetTokenType() == ttQuestion )
  1411. {
  1412. asCByteCode tmpBC(engine);
  1413. // Place the type id on the stack as a hidden parameter
  1414. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1415. // Insert the code before the expression code
  1416. tmpBC.AddCode(&ctx->bc);
  1417. ctx->bc.AddCode(&tmpBC);
  1418. }
  1419. // If the expression is marked as clean, then it can be used directly
  1420. // without the need to allocate another temporary value as it is known
  1421. // that the argument has no other value than the default
  1422. if( ctx->isCleanArg )
  1423. {
  1424. // Must be a local variable
  1425. asASSERT( ctx->type.isVariable );
  1426. }
  1427. else
  1428. {
  1429. // Null handles and void expressions must be marked as explicit
  1430. // handles for correct treatement in MoveArgsToStack
  1431. if (dt.IsNullHandle())
  1432. ctx->type.isExplicitHandle = true;
  1433. // Make sure the variable is not used in the expression
  1434. dt.MakeReadOnly(false);
  1435. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1436. if( dt.IsPrimitive() )
  1437. {
  1438. ctx->type.SetVariable(dt, offset, true);
  1439. PushVariableOnStack(ctx, true);
  1440. }
  1441. else
  1442. {
  1443. // Allocate and construct the temporary object
  1444. asCByteCode tmpBC(engine);
  1445. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1446. // Insert the code before the expression code
  1447. tmpBC.AddCode(&ctx->bc);
  1448. ctx->bc.AddCode(&tmpBC);
  1449. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1450. asCExprValue type;
  1451. type.Set(dt);
  1452. type.isTemporary = true;
  1453. type.stackOffset = (short)offset;
  1454. type.isExplicitHandle = ctx->type.isExplicitHandle;
  1455. ctx->type = type;
  1456. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1457. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1458. ctx->bc.Instr(asBC_RDSPtr);
  1459. }
  1460. // After the function returns the temporary variable will
  1461. // be assigned to the expression, if it is a valid lvalue
  1462. }
  1463. }
  1464. else if( refType == asTM_INOUTREF )
  1465. {
  1466. ProcessPropertyGetAccessor(ctx, node);
  1467. // Add the type id as hidden arg if the parameter is a ? type
  1468. if( paramType->GetTokenType() == ttQuestion )
  1469. {
  1470. asCByteCode tmpBC(engine);
  1471. // Place the type id on the stack as a hidden parameter
  1472. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1473. // Insert the code before the expression code
  1474. tmpBC.AddCode(&ctx->bc);
  1475. ctx->bc.AddCode(&tmpBC);
  1476. }
  1477. // Literal constants cannot be passed to inout ref arguments
  1478. if( !ctx->type.isVariable &&
  1479. ctx->type.isConstant &&
  1480. !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
  1481. {
  1482. // Unless unsafe references are turned on and the reference is const
  1483. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1484. {
  1485. // Since the parameter is a const & make a copy.
  1486. ConvertToTempVariable(ctx);
  1487. ctx->type.dataType.MakeReadOnly(true);
  1488. }
  1489. else
  1490. {
  1491. Error(TXT_NOT_VALID_REFERENCE, node);
  1492. return -1;
  1493. }
  1494. }
  1495. // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
  1496. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1497. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1498. // Only objects that support object handles
  1499. // can be guaranteed to be safe. Local variables are
  1500. // already safe, so there is no need to add an extra
  1501. // references
  1502. if( !engine->ep.allowUnsafeReferences &&
  1503. !ctx->type.isVariable &&
  1504. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1505. !ctx->type.dataType.IsObjectHandle() &&
  1506. ((ctx->type.dataType.GetBehaviour()->addref &&
  1507. ctx->type.dataType.GetBehaviour()->release) ||
  1508. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1509. ctx->type.dataType.IsFuncdef()) )
  1510. {
  1511. // Store a handle to the object as local variable
  1512. asCExprContext tmp(engine);
  1513. dt = ctx->type.dataType;
  1514. dt.MakeHandle(true);
  1515. dt.MakeReference(false);
  1516. dt.MakeReadOnly(false);
  1517. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1518. // Copy the handle
  1519. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1520. ctx->bc.Instr(asBC_RDSPtr);
  1521. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1522. if( ctx->type.dataType.IsFuncdef() )
  1523. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1524. else
  1525. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1526. ctx->bc.Instr(asBC_PopPtr);
  1527. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1528. dt.MakeHandle(false);
  1529. dt.MakeReference(true);
  1530. // Release previous temporary variable stored in the context (if any)
  1531. if( ctx->type.isTemporary )
  1532. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1533. ctx->type.SetVariable(dt, offset, true);
  1534. }
  1535. // Make sure the reference to the value is on the stack
  1536. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1537. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1538. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1539. Dereference(ctx, true);
  1540. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1541. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1542. else if( ctx->type.dataType.IsPrimitive() )
  1543. ctx->bc.Instr(asBC_PshRPtr);
  1544. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1545. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1546. }
  1547. }
  1548. else
  1549. {
  1550. ProcessPropertyGetAccessor(ctx, node);
  1551. if( dt.IsPrimitive() )
  1552. {
  1553. IsVariableInitialized(&ctx->type, node);
  1554. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1555. // Implicitly convert primitives to the parameter type
  1556. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1557. if( ctx->type.isVariable )
  1558. {
  1559. PushVariableOnStack(ctx, dt.IsReference());
  1560. }
  1561. else if( ctx->type.isConstant )
  1562. {
  1563. ConvertToVariable(ctx);
  1564. PushVariableOnStack(ctx, dt.IsReference());
  1565. }
  1566. }
  1567. else
  1568. {
  1569. IsVariableInitialized(&ctx->type, node);
  1570. // Implicitly convert primitives to the parameter type
  1571. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1572. // Was the conversion successful?
  1573. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1574. {
  1575. asCString str;
  1576. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1577. Error(str, node);
  1578. ctx->type.Set(dt);
  1579. return -1;
  1580. }
  1581. if( dt.IsObjectHandle() )
  1582. ctx->type.isExplicitHandle = true;
  1583. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1584. {
  1585. // Objects passed by value must be placed in temporary variables
  1586. // so that they are guaranteed to not be referenced anywhere else.
  1587. // The object must also be allocated on the heap, as the memory will
  1588. // be deleted by the called function.
  1589. // Handles passed by value must also be placed in a temporary variable
  1590. // to guarantee that the object referred to isn't freed too early.
  1591. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1592. // Don't make temporary copies of handles if it is going to be used
  1593. // for handle assignment anyway, i.e. REFCPY.
  1594. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
  1595. PrepareTemporaryVariable(node, ctx, true);
  1596. }
  1597. }
  1598. }
  1599. // Don't put any pointer on the stack yet
  1600. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1601. {
  1602. // &inout parameter may leave the reference on the stack already
  1603. // references considered safe too, i.e. when the life time is known
  1604. if( refType != asTM_INOUTREF && !ctx->type.isRefSafe )
  1605. {
  1606. asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy );
  1607. if( ctx->type.isVariable || ctx->type.isTemporary )
  1608. {
  1609. ctx->bc.Instr(asBC_PopPtr);
  1610. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1611. ProcessDeferredParams(ctx);
  1612. }
  1613. }
  1614. }
  1615. return 0;
  1616. }
  1617. int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1618. {
  1619. // When a match has been found, compile the final byte code using correct parameter types
  1620. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1621. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1622. // If the function being called is the opAssign or copy constructor for the same type
  1623. // as the argument, then we should avoid making temporary copy of the argument
  1624. bool makingCopy = false;
  1625. if( descr->parameterTypes.GetLength() == 1 &&
  1626. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1627. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1628. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1629. makingCopy = true;
  1630. // Add code for arguments
  1631. asCExprContext e(engine);
  1632. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1633. {
  1634. // Make sure PrepareArgument doesn't use any variable that is already
  1635. // being used by the argument or any of the following argument expressions
  1636. int l = int(reservedVariables.GetLength());
  1637. for( int m = n; m >= 0; m-- )
  1638. args[m]->bc.GetVarsUsed(reservedVariables);
  1639. int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1640. reservedVariables.SetLength(l);
  1641. if (r < 0)
  1642. return r;
  1643. }
  1644. bc->AddCode(&e.bc);
  1645. return 0;
  1646. }
  1647. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1648. {
  1649. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1650. int offset = 0;
  1651. if( addOneToOffset )
  1652. offset += AS_PTR_SIZE;
  1653. // The address of where the return value should be stored is push on top of the arguments
  1654. if( descr->DoesReturnOnStack() )
  1655. offset += AS_PTR_SIZE;
  1656. #ifdef AS_DEBUG
  1657. // If the function being called is the opAssign or copy constructor for the same type
  1658. // as the argument, then we should avoid making temporary copy of the argument
  1659. bool makingCopy = false;
  1660. if( descr->parameterTypes.GetLength() == 1 &&
  1661. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1662. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1663. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1664. makingCopy = true;
  1665. #endif
  1666. // Move the objects that are sent by value to the stack just before the call
  1667. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1668. {
  1669. if( descr->parameterTypes[n].IsReference() )
  1670. {
  1671. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1672. {
  1673. if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe )
  1674. {
  1675. #ifdef AS_DEBUG
  1676. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1677. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1678. #endif
  1679. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1680. {
  1681. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1682. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1683. // as the value allocated on the stack is guaranteed to be safe
  1684. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1685. else
  1686. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1687. }
  1688. }
  1689. if( args[n]->type.dataType.IsObjectHandle() )
  1690. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1691. }
  1692. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1693. {
  1694. // If the argument is already known to be safe, i.e. has a guaranteed lifetime,
  1695. // then the address on the stack is already pointing to the correct object so no
  1696. // need to do anything else
  1697. if (!args[n]->type.isRefSafe)
  1698. {
  1699. if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1700. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1701. !args[n]->type.dataType.IsObjectHandle())
  1702. {
  1703. // Send the object as a reference to the object,
  1704. // and not to the variable holding the object
  1705. if (!IsVariableOnHeap(args[n]->type.stackOffset))
  1706. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1707. // as the value allocated on the stack is guaranteed to be safe
  1708. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1709. else
  1710. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1711. }
  1712. else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1713. args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
  1714. {
  1715. // The object handle is being passed as an object, so dereference it before
  1716. // the call so the reference will be to the object rather than to the handle
  1717. if (engine->ep.disallowValueAssignForRefType)
  1718. {
  1719. // With disallow value assign all ref type objects are always passed by handle
  1720. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1721. }
  1722. else
  1723. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1724. }
  1725. else
  1726. {
  1727. // If the variable is really an argument of @& type, then it is necessary
  1728. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1729. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1730. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1731. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1732. else
  1733. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1734. }
  1735. }
  1736. }
  1737. }
  1738. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1739. {
  1740. asASSERT(!args[n]->type.isRefSafe);
  1741. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1742. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1743. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1744. // The pointer in the variable will be moved to the stack
  1745. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1746. // Deallocate the variable slot so it can be reused, but do not attempt to
  1747. // free the content of the variable since it was moved to the stack for the call
  1748. DeallocateVariable(args[n]->type.stackOffset);
  1749. args[n]->type.isTemporary = false;
  1750. }
  1751. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1752. }
  1753. }
  1754. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1755. {
  1756. asASSERT(node->nodeType == snArgList);
  1757. // Count arguments
  1758. asCScriptNode *arg = node->firstChild;
  1759. int argCount = 0;
  1760. while( arg )
  1761. {
  1762. if( arg->nodeType != snNamedArgument )
  1763. argCount++;
  1764. arg = arg->next;
  1765. }
  1766. // Prepare the arrays
  1767. args.SetLength(argCount);
  1768. int n;
  1769. for( n = 0; n < argCount; n++ )
  1770. args[n] = 0;
  1771. n = argCount-1;
  1772. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1773. bool anyErrors = false, inPositionalArguments = false;
  1774. arg = node->lastChild;
  1775. while( arg )
  1776. {
  1777. asCScriptNode *asgNode = arg, *namedNode = 0;
  1778. if( asgNode->nodeType == snNamedArgument )
  1779. {
  1780. if( inPositionalArguments )
  1781. {
  1782. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1783. return -1;
  1784. }
  1785. asgNode = arg->firstChild->next;
  1786. namedNode = arg->firstChild;
  1787. asASSERT( namedNode->nodeType == snIdentifier );
  1788. }
  1789. else
  1790. inPositionalArguments = true;
  1791. asCExprContext expr(engine);
  1792. int r = CompileAssignment(asgNode, &expr);
  1793. if( r < 0 ) anyErrors = true;
  1794. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1795. if( ctx == 0 )
  1796. {
  1797. // Out of memory
  1798. return -1;
  1799. }
  1800. MergeExprBytecodeAndType(ctx, &expr);
  1801. if( inPositionalArguments )
  1802. {
  1803. args[n] = ctx;
  1804. n--;
  1805. }
  1806. else
  1807. {
  1808. asSNamedArgument namedArg;
  1809. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1810. namedArg.ctx = ctx;
  1811. // Error out when multiple arguments with the same name are passed
  1812. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1813. {
  1814. if( namedArgs[a].name == namedArg.name )
  1815. {
  1816. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1817. anyErrors = true;
  1818. break;
  1819. }
  1820. }
  1821. namedArgs.PushLast(namedArg);
  1822. }
  1823. arg = arg->prev;
  1824. }
  1825. return anyErrors ? -1 : 0;
  1826. }
  1827. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1828. {
  1829. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1830. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1831. return 0;
  1832. // Make sure to use the real function for virtual functions
  1833. if( func->funcType == asFUNC_VIRTUAL )
  1834. {
  1835. asASSERT( objectType );
  1836. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1837. }
  1838. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1839. bool anyErrors = false;
  1840. int prevReservedVars = reservedVariables.GetLength();
  1841. int explicitArgs = (int)args.GetLength();
  1842. for( int p = 0; p < explicitArgs; p++ )
  1843. args[p]->bc.GetVarsUsed(reservedVariables);
  1844. // Make space for all the new arguments
  1845. args.SetLength(func->parameterTypes.GetLength());
  1846. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1847. args[c] = 0;
  1848. // Add the named arguments to the argument list in the right position
  1849. if( namedArgs )
  1850. {
  1851. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1852. {
  1853. asSNamedArgument &named = (*namedArgs)[n];
  1854. named.ctx->bc.GetVarsUsed(reservedVariables);
  1855. // Find the right spot to put it in
  1856. asUINT index = asUINT(-1);
  1857. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1858. {
  1859. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1860. {
  1861. index = j;
  1862. break;
  1863. }
  1864. }
  1865. asASSERT( index < args.GetLength() );
  1866. args[index] = named.ctx;
  1867. named.ctx = 0;
  1868. }
  1869. }
  1870. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1871. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1872. {
  1873. if( args[n] != 0 ) continue;
  1874. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1875. // Parse the default arg string
  1876. asCParser parser(builder);
  1877. asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength());
  1878. int r = parser.ParseExpression(code);
  1879. if( r < 0 )
  1880. {
  1881. asCString msg;
  1882. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1883. Error(msg, node);
  1884. anyErrors = true;
  1885. continue;
  1886. }
  1887. asCScriptNode *arg = parser.GetScriptNode();
  1888. // Temporarily set the script code to the default arg expression
  1889. asCScriptCode *origScript = script;
  1890. script = code;
  1891. // Don't allow the expression to access local variables
  1892. isCompilingDefaultArg = true;
  1893. // Temporarily set the namespace in the output function to the namespace of the called
  1894. // function so that the default arguments are evaluated in the correct namespace
  1895. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1896. outFunc->nameSpace = func->nameSpace;
  1897. asCExprContext expr(engine);
  1898. r = CompileExpression(arg, &expr);
  1899. // Restore the namespace
  1900. outFunc->nameSpace = origNameSpace;
  1901. // Don't allow address of class method
  1902. if( expr.IsClassMethod() )
  1903. {
  1904. // TODO: Improve error message
  1905. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1906. r = -1;
  1907. }
  1908. // Make sure the expression can be implicitly converted to the parameter type
  1909. if( r >= 0 )
  1910. {
  1911. asCArray<int> funcs;
  1912. funcs.PushLast(func->id);
  1913. asCArray<asSOverloadCandidate> matches;
  1914. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1915. {
  1916. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1917. r = -1;
  1918. }
  1919. }
  1920. isCompilingDefaultArg = false;
  1921. script = origScript;
  1922. if( r < 0 )
  1923. {
  1924. asCString msg;
  1925. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1926. Error(msg, node);
  1927. anyErrors = true;
  1928. continue;
  1929. }
  1930. args[n] = asNEW(asCExprContext)(engine);
  1931. if( args[n] == 0 )
  1932. {
  1933. // Out of memory
  1934. reservedVariables.SetLength(prevReservedVars);
  1935. return -1;
  1936. }
  1937. MergeExprBytecodeAndType(args[n], &expr);
  1938. }
  1939. reservedVariables.SetLength(prevReservedVars);
  1940. return anyErrors ? -1 : 0;
  1941. }
  1942. 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)
  1943. {
  1944. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1945. asUINT cost = 0;
  1946. asUINT n;
  1947. if( funcs.GetLength() > 0 )
  1948. {
  1949. // Check the number of parameters in the found functions
  1950. asUINT totalArgs = (asUINT)args.GetLength();
  1951. if( namedArgs != 0 )
  1952. totalArgs += (asUINT)namedArgs->GetLength();
  1953. for( n = 0; n < funcs.GetLength(); ++n )
  1954. {
  1955. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1956. if( desc->parameterTypes.GetLength() != totalArgs )
  1957. {
  1958. bool noMatch = true;
  1959. if( totalArgs < desc->parameterTypes.GetLength() )
  1960. {
  1961. // For virtual functions, the default args are defined in the real function of the object
  1962. if( desc->funcType == asFUNC_VIRTUAL )
  1963. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1964. // Count the number of default args
  1965. asUINT defaultArgs = 0;
  1966. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1967. if( desc->defaultArgs[d] )
  1968. defaultArgs++;
  1969. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1970. noMatch = false;
  1971. }
  1972. if( noMatch )
  1973. {
  1974. // remove it from the list
  1975. if( n == funcs.GetLength()-1 )
  1976. funcs.PopLast();
  1977. else
  1978. funcs[n] = funcs.PopLast();
  1979. n--;
  1980. }
  1981. }
  1982. }
  1983. // Match functions with the parameters, and discard those that do not match
  1984. asCArray<asSOverloadCandidate> matchingFuncs;
  1985. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1986. for ( n = 0; n < funcs.GetLength(); ++n )
  1987. {
  1988. matchingFuncs[n].funcId = funcs[n];
  1989. matchingFuncs[n].cost = 0;
  1990. }
  1991. // Match positionally passed arguments
  1992. for( n = 0; n < args.GetLength(); ++n )
  1993. {
  1994. asCArray<asSOverloadCandidate> tempFuncs;
  1995. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1996. // Intersect the found functions with the list of matching functions
  1997. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1998. {
  1999. asUINT c;
  2000. for( c = 0; c < tempFuncs.GetLength(); c++ )
  2001. {
  2002. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  2003. {
  2004. // Sum argument cost
  2005. matchingFuncs[f].cost += tempFuncs[c].cost;
  2006. break;
  2007. } // End if match
  2008. }
  2009. // Was the function a match?
  2010. if( c == tempFuncs.GetLength() )
  2011. {
  2012. // No, remove it from the list
  2013. if( f == matchingFuncs.GetLength()-1 )
  2014. matchingFuncs.PopLast();
  2015. else
  2016. matchingFuncs[f] = matchingFuncs.PopLast();
  2017. f--;
  2018. }
  2019. }
  2020. }
  2021. // Match named arguments
  2022. if( namedArgs != 0 )
  2023. {
  2024. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  2025. {
  2026. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  2027. if( desc->funcType == asFUNC_VIRTUAL )
  2028. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  2029. // Match every named argument to an argument in the function
  2030. for( n = 0; n < namedArgs->GetLength(); ++n )
  2031. (*namedArgs)[n].match = asUINT(-1);
  2032. bool matchedAll = true;
  2033. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  2034. {
  2035. asUINT match = asUINT(-1);
  2036. for( n = 0; n < namedArgs->GetLength(); ++n )
  2037. {
  2038. asSNamedArgument &namedArg = (*namedArgs)[n];
  2039. if( desc->parameterNames[j] == namedArg.name )
  2040. {
  2041. namedArg.match = j;
  2042. match = n;
  2043. break;
  2044. }
  2045. }
  2046. // Check that every position is filled somehow
  2047. if( j >= args.GetLength() )
  2048. {
  2049. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  2050. {
  2051. // No argument was found for this, and there is no
  2052. // default, so it doesn't work.
  2053. matchedAll = false;
  2054. break;
  2055. }
  2056. }
  2057. else
  2058. {
  2059. if( match != asUINT(-1) )
  2060. {
  2061. // Can't name an argument that was already passed
  2062. matchedAll = false;
  2063. break;
  2064. }
  2065. }
  2066. }
  2067. // Check that every named argument was matched
  2068. if( matchedAll )
  2069. {
  2070. for( n = 0; n < namedArgs->GetLength(); ++n )
  2071. {
  2072. asSNamedArgument &named = (*namedArgs)[n];
  2073. if( named.match == asUINT(-1) )
  2074. {
  2075. matchedAll = false;
  2076. break;
  2077. }
  2078. // Add to the cost
  2079. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  2080. if( cost == asUINT(-1) )
  2081. {
  2082. matchedAll = false;
  2083. break;
  2084. }
  2085. matchingFuncs[i].cost += cost;
  2086. }
  2087. }
  2088. if( !matchedAll )
  2089. {
  2090. // Remove the function, we didn't match all the arguments.
  2091. if( i == matchingFuncs.GetLength()-1 )
  2092. matchingFuncs.PopLast();
  2093. else
  2094. matchingFuncs[i] = matchingFuncs.PopLast();
  2095. i--;
  2096. }
  2097. }
  2098. }
  2099. // Select the overload(s) with the lowest overall cost
  2100. funcs.SetLength(0);
  2101. asUINT bestCost = asUINT(-1);
  2102. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2103. {
  2104. cost = matchingFuncs[n].cost;
  2105. if( cost < bestCost )
  2106. {
  2107. funcs.SetLength(0);
  2108. bestCost = cost;
  2109. }
  2110. if( cost == bestCost )
  2111. funcs.PushLast( matchingFuncs[n].funcId );
  2112. }
  2113. // Cost returned is equivalent to the best cost discovered
  2114. cost = bestCost;
  2115. }
  2116. if( !isConstMethod )
  2117. FilterConst(funcs);
  2118. if( funcs.GetLength() != 1 && !silent )
  2119. {
  2120. // Build a readable string of the function with parameter types
  2121. bool attemptsPassingClassMethod = false;
  2122. asCString str;
  2123. if( scope != "" && scope != "::" )
  2124. str = scope + "::";
  2125. str += name;
  2126. str += "(";
  2127. for( n = 0; n < args.GetLength(); n++ )
  2128. {
  2129. if( n > 0 )
  2130. str += ", ";
  2131. if( args[n]->methodName != "" )
  2132. {
  2133. if( args[n]->IsClassMethod() )
  2134. {
  2135. attemptsPassingClassMethod = true;
  2136. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2137. str += "::";
  2138. }
  2139. str += args[n]->methodName;
  2140. }
  2141. else if (args[n]->IsAnonymousInitList())
  2142. {
  2143. str += "{...}";
  2144. }
  2145. else
  2146. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2147. }
  2148. if( namedArgs != 0 )
  2149. {
  2150. for( n = 0; n < namedArgs->GetLength(); n++ )
  2151. {
  2152. if( n > 0 || args.GetLength() )
  2153. str += ", ";
  2154. asSNamedArgument &named = (*namedArgs)[n];
  2155. str += named.name;
  2156. str += ": ";
  2157. if( named.ctx->methodName != "" )
  2158. str += named.ctx->methodName;
  2159. else
  2160. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2161. }
  2162. }
  2163. str += ")";
  2164. if( isConstMethod )
  2165. str += " const";
  2166. if( objectType && scope == "" )
  2167. str = objectType->name + "::" + str;
  2168. if( funcs.GetLength() == 0 )
  2169. {
  2170. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2171. Error(str, node);
  2172. if( attemptsPassingClassMethod )
  2173. {
  2174. // Class methods must use delegate objects
  2175. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2176. }
  2177. else
  2178. {
  2179. // Print the list of candidates
  2180. if( origFuncs.GetLength() > 0 )
  2181. {
  2182. int r = 0, c = 0;
  2183. asASSERT( node );
  2184. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2185. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2186. PrintMatchingFuncs(origFuncs, node, objectType);
  2187. }
  2188. }
  2189. }
  2190. else
  2191. {
  2192. asASSERT( attemptsPassingClassMethod == false );
  2193. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2194. Error(str, node);
  2195. PrintMatchingFuncs(funcs, node, objectType);
  2196. }
  2197. }
  2198. return cost;
  2199. }
  2200. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2201. {
  2202. if( node && node->nodeType == snAssignment )
  2203. {
  2204. int r = CompileAssignment(node, &compiledCtx);
  2205. if( r >= 0 )
  2206. {
  2207. // Must not have unused ambiguous names
  2208. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2209. {
  2210. // TODO: Should mention that the problem is the ambiguous name
  2211. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2212. return false;
  2213. }
  2214. // Must not have unused anonymous functions
  2215. if (compiledCtx.IsLambda())
  2216. {
  2217. // TODO: Should mention that the problem is the anonymous function
  2218. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2219. return false;
  2220. }
  2221. // Must not be a null handle
  2222. if (compiledCtx.type.dataType.IsNullHandle())
  2223. {
  2224. // TODO: Should mention that the problem is the null pointer
  2225. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2226. return false;
  2227. }
  2228. asCDataType newType = compiledCtx.type.dataType;
  2229. // Handle const qualifier on auto
  2230. if (type.IsReadOnly())
  2231. newType.MakeReadOnly(true);
  2232. else if (newType.IsPrimitive())
  2233. newType.MakeReadOnly(false);
  2234. // Handle reference/value stuff
  2235. newType.MakeReference(false);
  2236. if (!newType.IsObjectHandle())
  2237. {
  2238. // We got a value object or an object reference.
  2239. // Turn the variable into a handle if specified
  2240. // as auto@, otherwise make it a 'value'.
  2241. if (type.IsHandleToAuto())
  2242. {
  2243. if (newType.MakeHandle(true) < 0)
  2244. {
  2245. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2246. return false;
  2247. }
  2248. }
  2249. }
  2250. // Implicit handle types should always be handles
  2251. if (newType.GetTypeInfo() &&
  2252. (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
  2253. newType.MakeHandle(true);
  2254. // For types that support handles auto should prefer handle
  2255. // as it is more efficient than making a copy
  2256. // TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want?
  2257. if( newType.SupportHandles() )
  2258. newType.MakeHandle(true);
  2259. type = newType;
  2260. return true;
  2261. }
  2262. return false;
  2263. }
  2264. else
  2265. {
  2266. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2267. type = asCDataType::CreatePrimitive(ttInt, false);
  2268. return false;
  2269. }
  2270. }
  2271. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2272. {
  2273. // Get the data type
  2274. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2275. // Declare all variables in this declaration
  2276. asCScriptNode *node = decl->firstChild->next;
  2277. while( node )
  2278. {
  2279. // If this is an auto type, we have to compile the assignment now to figure out the type
  2280. asCExprContext compiledCtx(engine);
  2281. bool preCompiled = false;
  2282. if (type.IsAuto())
  2283. {
  2284. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2285. if (!preCompiled)
  2286. {
  2287. // If it wasn't possible to determine the type from the expression then there
  2288. // is no need to continue with the initialization. The error was already reported
  2289. // in CompileAutoType.
  2290. return;
  2291. }
  2292. }
  2293. // Is the type allowed?
  2294. if( !type.CanBeInstantiated() )
  2295. {
  2296. asCString str;
  2297. if( type.IsAbstractClass() )
  2298. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2299. else if( type.IsInterface() )
  2300. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2301. else
  2302. // TODO: Improve error message to explain why
  2303. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2304. Error(str, node);
  2305. // Don't continue, as it will most likely lead to further
  2306. // errors that may just mislead the script writer
  2307. return;
  2308. }
  2309. // A shared object may not declare variables of non-shared types
  2310. if( outFunc->IsShared() )
  2311. {
  2312. asCTypeInfo *ot = type.GetTypeInfo();
  2313. if( ot && !ot->IsShared() )
  2314. {
  2315. asCString msg;
  2316. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2317. Error(msg, decl);
  2318. }
  2319. }
  2320. // Get the name of the identifier
  2321. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2322. // Verify that the name isn't used by a dynamic data type
  2323. // TODO: Must check against registered funcdefs too
  2324. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2325. {
  2326. asCString str;
  2327. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2328. Error(str, node);
  2329. }
  2330. int offset = AllocateVariable(type, false);
  2331. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2332. {
  2333. // TODO: It might be an out-of-memory too
  2334. asCString str;
  2335. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2336. Error(str, node);
  2337. // Don't continue after this error, as it will just
  2338. // lead to more errors that are likely false
  2339. return;
  2340. }
  2341. else
  2342. {
  2343. // Warn if this variable hides another variable in a higher scope
  2344. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2345. {
  2346. asCString str;
  2347. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2348. Warning(str, node);
  2349. }
  2350. }
  2351. // Add marker that the variable has been declared
  2352. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2353. outFunc->AddVariable(name, type, offset);
  2354. // Keep the node for the variable decl
  2355. asCScriptNode *varNode = node;
  2356. node = node->next;
  2357. if( node == 0 || node->nodeType == snIdentifier )
  2358. {
  2359. // Initialize with default constructor
  2360. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2361. }
  2362. else
  2363. {
  2364. // Compile the initialization expression
  2365. asQWORD constantValue = 0;
  2366. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2367. {
  2368. // Check if the variable should be marked as pure constant
  2369. if( type.IsPrimitive() && type.IsReadOnly() )
  2370. {
  2371. sVariable *v = variables->GetVariable(name.AddressOf());
  2372. v->isPureConstant = true;
  2373. v->constantValue = constantValue;
  2374. }
  2375. }
  2376. node = node->next;
  2377. }
  2378. }
  2379. bc->OptimizeLocally(tempVariableOffsets);
  2380. }
  2381. // Returns true if the initialization expression is a constant expression
  2382. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2383. {
  2384. bool isConstantExpression = false;
  2385. if( node && node->nodeType == snArgList )
  2386. {
  2387. // Make sure it is an object and not a handle
  2388. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2389. {
  2390. Error(TXT_MUST_BE_OBJECT, node);
  2391. }
  2392. else
  2393. {
  2394. // Compile the arguments
  2395. asCArray<asCExprContext *> args;
  2396. asCArray<asSNamedArgument> namedArgs;
  2397. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2398. {
  2399. // Find all constructors
  2400. asCArray<int> funcs;
  2401. asSTypeBehaviour *beh = type.GetBehaviour();
  2402. if( beh )
  2403. {
  2404. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2405. funcs = beh->factories;
  2406. else
  2407. funcs = beh->constructors;
  2408. }
  2409. asCString str = type.Format(outFunc->nameSpace);
  2410. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2411. if( funcs.GetLength() == 1 )
  2412. {
  2413. // Add the default values for arguments not explicitly supplied
  2414. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2415. if( r == asSUCCESS )
  2416. {
  2417. asCExprContext ctx(engine);
  2418. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2419. {
  2420. if( isVarGlobOrMem == 0 )
  2421. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2422. else
  2423. {
  2424. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2425. ctx.bc.Instr(asBC_RDSPtr);
  2426. if( isVarGlobOrMem == 1 )
  2427. {
  2428. // Store the returned handle in the global variable
  2429. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2430. }
  2431. else
  2432. {
  2433. // Store the returned handle in the member
  2434. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2435. ctx.bc.Instr(asBC_RDSPtr);
  2436. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2437. }
  2438. if( type.IsFuncdef())
  2439. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2440. else
  2441. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2442. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2443. }
  2444. // Pop the reference left by the function call
  2445. ctx.bc.Instr(asBC_PopPtr);
  2446. }
  2447. else
  2448. {
  2449. bool onHeap = false;
  2450. if( isVarGlobOrMem == 0 )
  2451. {
  2452. // When the object is allocated on the heap, the address where the
  2453. // reference will be stored must be pushed on the stack before the
  2454. // arguments. This reference on the stack is safe, even if the script
  2455. // is suspended during the evaluation of the arguments.
  2456. onHeap = IsVariableOnHeap(offset);
  2457. if( onHeap )
  2458. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2459. }
  2460. else if( isVarGlobOrMem == 1 )
  2461. {
  2462. // Push the address of the location where the variable will be stored on the stack.
  2463. // This reference is safe, because the addresses of the global variables cannot change.
  2464. onHeap = true;
  2465. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2466. }
  2467. else
  2468. {
  2469. // Value types may be allocated inline if they are POD types
  2470. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2471. if( onHeap )
  2472. {
  2473. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2474. ctx.bc.Instr(asBC_RDSPtr);
  2475. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2476. }
  2477. }
  2478. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2479. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2480. // When the object is allocated on the stack, the address to the
  2481. // object is pushed on the stack after the arguments as the object pointer
  2482. if( !onHeap )
  2483. {
  2484. if( isVarGlobOrMem == 2 )
  2485. {
  2486. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2487. ctx.bc.Instr(asBC_RDSPtr);
  2488. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2489. }
  2490. else
  2491. {
  2492. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2493. }
  2494. }
  2495. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2496. if( isVarGlobOrMem == 0 )
  2497. {
  2498. // Mark the object in the local variable as initialized
  2499. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2500. }
  2501. }
  2502. bc->AddCode(&ctx.bc);
  2503. }
  2504. }
  2505. }
  2506. // Cleanup
  2507. for( asUINT n = 0; n < args.GetLength(); n++ )
  2508. if( args[n] )
  2509. {
  2510. asDELETE(args[n], asCExprContext);
  2511. }
  2512. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2513. if( namedArgs[n].ctx )
  2514. {
  2515. asDELETE(namedArgs[n].ctx, asCExprContext);
  2516. }
  2517. }
  2518. }
  2519. else if( node && node->nodeType == snInitList )
  2520. {
  2521. asCExprValue ti;
  2522. ti.Set(type);
  2523. ti.isVariable = (isVarGlobOrMem == 0);
  2524. ti.isTemporary = false;
  2525. ti.stackOffset = (short)offset;
  2526. ti.isLValue = true;
  2527. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2528. }
  2529. else if( node && node->nodeType == snAssignment )
  2530. {
  2531. // Compile the expression
  2532. asCExprContext newExpr(engine);
  2533. asCExprContext* expr;
  2534. int r = 0;
  2535. if( preCompiled )
  2536. {
  2537. expr = preCompiled;
  2538. }
  2539. else
  2540. {
  2541. expr = &newExpr;
  2542. r = CompileAssignment(node, expr);
  2543. }
  2544. // handles initialized with null doesn't need any bytecode
  2545. // since handles will be initialized to null by default anyway
  2546. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2547. return false;
  2548. // Look for appropriate constructor
  2549. asCArray<int> funcs;
  2550. asCArray<asCExprContext *> args;
  2551. // Handles must use the handle assignment operation.
  2552. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2553. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2554. // Only do this if the expression is of the same type, as the expression is an assignment
  2555. // and an initialization constructor may not have the same meaning.
  2556. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2557. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2558. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2559. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2560. {
  2561. asSTypeBehaviour *beh = type.GetBehaviour();
  2562. if( beh )
  2563. {
  2564. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2565. funcs = beh->factories;
  2566. else
  2567. funcs = beh->constructors;
  2568. }
  2569. asCString str = type.Format(outFunc->nameSpace);
  2570. args.PushLast(expr);
  2571. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2572. // Make sure the argument is of the right type (and not just compatible with the expression)
  2573. if (funcs.GetLength() == 1)
  2574. {
  2575. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2576. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2577. funcs.PopLast();
  2578. }
  2579. }
  2580. if( funcs.GetLength() == 1 )
  2581. {
  2582. // Use the constructor
  2583. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2584. // Add the default values for arguments not explicitly supplied
  2585. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2586. if( r == asSUCCESS )
  2587. {
  2588. asCExprContext ctx(engine);
  2589. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2590. {
  2591. if( isVarGlobOrMem == 0 )
  2592. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2593. else
  2594. {
  2595. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2596. ctx.bc.Instr(asBC_RDSPtr);
  2597. if( isVarGlobOrMem == 1 )
  2598. {
  2599. // Store the returned handle in the global variable
  2600. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2601. }
  2602. else
  2603. {
  2604. // Store the returned handle in the member
  2605. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2606. ctx.bc.Instr(asBC_RDSPtr);
  2607. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2608. }
  2609. if( type.IsFuncdef() )
  2610. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2611. else
  2612. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2613. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2614. }
  2615. // Pop the reference left by the function call
  2616. ctx.bc.Instr(asBC_PopPtr);
  2617. }
  2618. else
  2619. {
  2620. bool onHeap = false;
  2621. if( isVarGlobOrMem == 0 )
  2622. {
  2623. // When the object is allocated on the heap, the address where the
  2624. // reference will be stored must be pushed on the stack before the
  2625. // arguments. This reference on the stack is safe, even if the script
  2626. // is suspended during the evaluation of the arguments.
  2627. onHeap = IsVariableOnHeap(offset);
  2628. if( onHeap )
  2629. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2630. }
  2631. else if( isVarGlobOrMem == 1 )
  2632. {
  2633. // Push the address of the location where the variable will be stored on the stack.
  2634. // This reference is safe, because the addresses of the global variables cannot change.
  2635. onHeap = true;
  2636. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2637. }
  2638. else
  2639. {
  2640. // Value types may be allocated inline if they are POD types
  2641. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2642. if( onHeap )
  2643. {
  2644. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2645. ctx.bc.Instr(asBC_RDSPtr);
  2646. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2647. }
  2648. }
  2649. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2650. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2651. // When the object is allocated on the stack, the address to the
  2652. // object is pushed on the stack after the arguments as the object pointer
  2653. if( !onHeap )
  2654. {
  2655. if( isVarGlobOrMem == 2 )
  2656. {
  2657. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2658. ctx.bc.Instr(asBC_RDSPtr);
  2659. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2660. }
  2661. else
  2662. {
  2663. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2664. }
  2665. }
  2666. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2667. if( isVarGlobOrMem == 0 )
  2668. {
  2669. // Mark the object in the local variable as initialized
  2670. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2671. }
  2672. }
  2673. bc->AddCode(&ctx.bc);
  2674. }
  2675. }
  2676. else
  2677. {
  2678. // Call the default constructur, then call the assignment operator
  2679. asCExprContext ctx(engine);
  2680. // Call the default constructor here
  2681. if( isVarGlobOrMem == 0 )
  2682. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2683. else if( isVarGlobOrMem == 1 )
  2684. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2685. else if( isVarGlobOrMem == 2 )
  2686. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2687. if( r >= 0 )
  2688. {
  2689. if( type.IsPrimitive() )
  2690. {
  2691. if( type.IsReadOnly() && expr->type.isConstant )
  2692. {
  2693. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2694. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2695. isConstantExpression = true;
  2696. *constantValue = expr->type.GetConstantData();
  2697. }
  2698. asCExprContext lctx(engine);
  2699. if( isVarGlobOrMem == 0 )
  2700. lctx.type.SetVariable(type, offset, false);
  2701. else if( isVarGlobOrMem == 1 )
  2702. {
  2703. lctx.type.Set(type);
  2704. lctx.type.dataType.MakeReference(true);
  2705. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2706. // we skip this as the bytecode won't be used anyway, only the constant value
  2707. if( offset >= 0 )
  2708. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2709. }
  2710. else
  2711. {
  2712. asASSERT( isVarGlobOrMem == 2 );
  2713. lctx.type.Set(type);
  2714. lctx.type.dataType.MakeReference(true);
  2715. // Load the reference of the primitive member into the register
  2716. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2717. lctx.bc.Instr(asBC_RDSPtr);
  2718. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2719. lctx.bc.Instr(asBC_PopRPtr);
  2720. }
  2721. lctx.type.dataType.MakeReadOnly(false);
  2722. lctx.type.isLValue = true;
  2723. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2724. ProcessDeferredParams(&ctx);
  2725. }
  2726. else
  2727. {
  2728. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2729. // just the copy constructor. Only if no appropriate constructor is
  2730. // available should the assignment operator be used.
  2731. asCExprContext lexpr(engine);
  2732. lexpr.type.Set(type);
  2733. if( isVarGlobOrMem == 0 )
  2734. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2735. else if( isVarGlobOrMem == 1 )
  2736. lexpr.type.dataType.MakeReference(true);
  2737. else if( isVarGlobOrMem == 2 )
  2738. {
  2739. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2740. lexpr.type.dataType.MakeReference(true);
  2741. }
  2742. // Allow initialization of constant variables
  2743. lexpr.type.dataType.MakeReadOnly(false);
  2744. if( type.IsObjectHandle() )
  2745. lexpr.type.isExplicitHandle = true;
  2746. if( isVarGlobOrMem == 0 )
  2747. {
  2748. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2749. lexpr.type.stackOffset = (short)offset;
  2750. lexpr.type.isVariable = true;
  2751. }
  2752. else if( isVarGlobOrMem == 1 )
  2753. {
  2754. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2755. }
  2756. else
  2757. {
  2758. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2759. lexpr.bc.Instr(asBC_RDSPtr);
  2760. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2761. lexpr.type.stackOffset = -1;
  2762. }
  2763. lexpr.type.isLValue = true;
  2764. // If left expression resolves into a registered type
  2765. // check if the assignment operator is overloaded, and check
  2766. // the type of the right hand expression. If none is found
  2767. // the default action is a direct copy if it is the same type
  2768. // and a simple assignment.
  2769. bool assigned = false;
  2770. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2771. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2772. {
  2773. bool useHndlAssign = false;
  2774. if (lexpr.type.dataType.IsHandleToAsHandleType())
  2775. {
  2776. useHndlAssign = true;
  2777. // Make sure the right hand expression is treated as a handle
  2778. if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() )
  2779. {
  2780. // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
  2781. // Convert the expression to a handle
  2782. if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
  2783. {
  2784. asCDataType to = expr->type.dataType;
  2785. to.MakeHandle(true);
  2786. to.MakeReference(true);
  2787. to.MakeHandleToConst(expr->type.dataType.IsReadOnly());
  2788. ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false);
  2789. asASSERT(expr->type.dataType.IsObjectHandle());
  2790. }
  2791. else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
  2792. {
  2793. // For the ASHANDLE type we'll simply set the expression as a handle
  2794. expr->type.dataType.MakeHandle(true);
  2795. }
  2796. if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles())
  2797. {
  2798. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  2799. }
  2800. expr->type.isExplicitHandle = true;
  2801. }
  2802. }
  2803. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2804. if( assigned )
  2805. {
  2806. // Pop the resulting value
  2807. if( !ctx.type.dataType.IsPrimitive() )
  2808. ctx.bc.Instr(asBC_PopPtr);
  2809. // Release the argument
  2810. ProcessDeferredParams(&ctx);
  2811. // Release temporary variable that may be allocated by the overloaded operator
  2812. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2813. }
  2814. }
  2815. if( !assigned )
  2816. {
  2817. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2818. // If the expression is constant and the variable also is constant
  2819. // then mark the variable as pure constant. This will allow the compiler
  2820. // to optimize expressions with this variable.
  2821. if( type.IsReadOnly() && expr->type.isConstant )
  2822. {
  2823. isConstantExpression = true;
  2824. *constantValue = expr->type.GetConstantQW();
  2825. }
  2826. // Add expression code to bytecode
  2827. MergeExprBytecode(&ctx, expr);
  2828. // Add byte code for storing value of expression in variable
  2829. ctx.bc.AddCode(&lexpr.bc);
  2830. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2831. // Release temporary variables used by expression
  2832. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2833. ctx.bc.Instr(asBC_PopPtr);
  2834. ProcessDeferredParams(&ctx);
  2835. }
  2836. }
  2837. }
  2838. bc->AddCode(&ctx.bc);
  2839. }
  2840. }
  2841. else
  2842. {
  2843. asASSERT( node == 0 );
  2844. // Call the default constructor here, as no explicit initialization is done
  2845. if( isVarGlobOrMem == 0 )
  2846. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2847. else if( isVarGlobOrMem == 1 )
  2848. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2849. else if( isVarGlobOrMem == 2 )
  2850. {
  2851. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2852. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2853. else
  2854. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2855. }
  2856. }
  2857. return isConstantExpression;
  2858. }
  2859. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2860. {
  2861. // Check if the type supports initialization lists
  2862. if( var->dataType.GetTypeInfo() == 0 ||
  2863. var->dataType.GetBehaviour()->listFactory == 0 )
  2864. {
  2865. asCString str;
  2866. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2867. Error(str, node);
  2868. return;
  2869. }
  2870. // Construct the buffer with the elements
  2871. // Find the list factory
  2872. int funcId = var->dataType.GetBehaviour()->listFactory;
  2873. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2874. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2875. // for small buffers so that the dynamic allocation is skipped
  2876. // Create a new special object type for the lists. Both asCRestore and the
  2877. // context exception handler will need this to know how to parse the buffer.
  2878. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2879. // Allocate a temporary variable to hold the pointer to the buffer
  2880. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2881. asUINT bufferSize = 0;
  2882. // Evaluate all elements of the list
  2883. asCExprContext valueExpr(engine);
  2884. asCScriptNode *el = node;
  2885. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2886. int elementsInSubList = -1;
  2887. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2888. asASSERT( r || patternNode == 0 );
  2889. if (r < 0)
  2890. {
  2891. asCString msg;
  2892. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2893. Error(msg, node);
  2894. }
  2895. // After all values have been evaluated we know the final size of the buffer
  2896. asCExprContext allocExpr(engine);
  2897. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2898. // Merge the bytecode into the final sequence
  2899. bc->AddCode(&allocExpr.bc);
  2900. bc->AddCode(&valueExpr.bc);
  2901. // The object itself is the last to be created and will receive the pointer to the buffer
  2902. asCArray<asCExprContext *> args;
  2903. asCExprContext arg1(engine);
  2904. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2905. arg1.type.dataType.MakeReference(true);
  2906. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2907. args.PushLast(&arg1);
  2908. asCExprContext ctx(engine);
  2909. if( var->isVariable )
  2910. {
  2911. asASSERT( isVarGlobOrMem == 0 );
  2912. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2913. {
  2914. ctx.bc.AddCode(&arg1.bc);
  2915. // Call factory and store the handle in the given variable
  2916. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2917. ctx.bc.Instr(asBC_PopPtr);
  2918. }
  2919. else
  2920. {
  2921. // Call the constructor
  2922. // When the object is allocated on the heap, the address where the
  2923. // reference will be stored must be pushed on the stack before the
  2924. // arguments. This reference on the stack is safe, even if the script
  2925. // is suspended during the evaluation of the arguments.
  2926. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2927. if( onHeap )
  2928. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2929. ctx.bc.AddCode(&arg1.bc);
  2930. // When the object is allocated on the stack, the address to the
  2931. // object is pushed on the stack after the arguments as the object pointer
  2932. if( !onHeap )
  2933. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2934. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2935. // Mark the object in the local variable as initialized
  2936. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2937. }
  2938. }
  2939. else
  2940. {
  2941. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2942. {
  2943. ctx.bc.AddCode(&arg1.bc);
  2944. PerformFunctionCall(funcId, &ctx, false, &args);
  2945. ctx.bc.Instr(asBC_RDSPtr);
  2946. if( isVarGlobOrMem == 1 )
  2947. {
  2948. // Store the returned handle in the global variable
  2949. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2950. }
  2951. else
  2952. {
  2953. // Store the returned handle in the member
  2954. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2955. ctx.bc.Instr(asBC_RDSPtr);
  2956. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2957. }
  2958. if (var->dataType.IsFuncdef())
  2959. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2960. else
  2961. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2962. ctx.bc.Instr(asBC_PopPtr);
  2963. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2964. }
  2965. else
  2966. {
  2967. bool onHeap = true;
  2968. // Put the address where the object pointer will be placed on the stack
  2969. if( isVarGlobOrMem == 1 )
  2970. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2971. else
  2972. {
  2973. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  2974. if( onHeap )
  2975. {
  2976. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2977. ctx.bc.Instr(asBC_RDSPtr);
  2978. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2979. }
  2980. }
  2981. // Add the address of the list buffer as the argument
  2982. ctx.bc.AddCode(&arg1.bc);
  2983. if( !onHeap )
  2984. {
  2985. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2986. ctx.bc.Instr(asBC_RDSPtr);
  2987. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2988. }
  2989. // Call the ALLOC instruction to allocate memory and invoke constructor
  2990. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2991. }
  2992. }
  2993. bc->AddCode(&ctx.bc);
  2994. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2995. // each element in the buffer so there is no need to do this manually
  2996. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  2997. ReleaseTemporaryVariable(bufferVar, bc);
  2998. }
  2999. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  3000. {
  3001. if( patternNode->type == asLPT_START )
  3002. {
  3003. if( valueNode == 0 || valueNode->nodeType != snInitList )
  3004. {
  3005. Error(TXT_EXPECTED_LIST, valueNode);
  3006. return -1;
  3007. }
  3008. // Compile all values until asLPT_END
  3009. patternNode = patternNode->next;
  3010. asCScriptNode *node = valueNode->firstChild;
  3011. while( patternNode->type != asLPT_END )
  3012. {
  3013. // Check for missing value here, else the error reporting will not have a source position to report the error for
  3014. if( node == 0 && patternNode->type == asLPT_TYPE )
  3015. {
  3016. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  3017. return -1;
  3018. }
  3019. asCScriptNode *errNode = node;
  3020. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  3021. if( r < 0 ) return r;
  3022. if( r == 1 )
  3023. {
  3024. asASSERT( engine->ep.disallowEmptyListElements );
  3025. // Empty elements in the middle are not allowed
  3026. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3027. }
  3028. asASSERT( patternNode );
  3029. }
  3030. if( node )
  3031. {
  3032. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  3033. return -1;
  3034. }
  3035. // Move to the next node
  3036. valueNode = valueNode->next;
  3037. patternNode = patternNode->next;
  3038. }
  3039. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  3040. {
  3041. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  3042. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  3043. asEListPatternNodeType repeatType = patternNode->type;
  3044. asCScriptNode *firstValue = valueNode;
  3045. // The following values will be repeated N times
  3046. patternNode = patternNode->next;
  3047. // Keep track of the patternNode so it can be reset
  3048. asSListPatternNode *nextNode = patternNode;
  3049. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  3050. if( bufferSize & 0x3 )
  3051. bufferSize += 4 - (bufferSize & 0x3);
  3052. // The first dword will hold the number of elements in the list
  3053. asDWORD currSize = bufferSize;
  3054. bufferSize += 4;
  3055. asUINT countElements = 0;
  3056. int elementsInSubSubList = -1;
  3057. asCExprContext ctx(engine);
  3058. while( valueNode )
  3059. {
  3060. patternNode = nextNode;
  3061. asCScriptNode *errNode = valueNode;
  3062. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  3063. if( r < 0 ) return r;
  3064. if( r == 0 )
  3065. countElements++;
  3066. else
  3067. {
  3068. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  3069. if( valueNode )
  3070. {
  3071. // Empty elements in the middle are not allowed
  3072. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3073. }
  3074. }
  3075. }
  3076. if( countElements == 0 )
  3077. {
  3078. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  3079. patternNode = nextNode;
  3080. if( patternNode->type == asLPT_TYPE )
  3081. patternNode = patternNode->next;
  3082. else if( patternNode->type == asLPT_START )
  3083. {
  3084. int subCount = 1;
  3085. do
  3086. {
  3087. patternNode = patternNode->next;
  3088. if( patternNode->type == asLPT_START )
  3089. subCount++;
  3090. else if( patternNode->type == asLPT_END )
  3091. subCount--;
  3092. } while( subCount > 0 );
  3093. patternNode = patternNode->next;
  3094. }
  3095. }
  3096. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  3097. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  3098. {
  3099. if( countElements < asUINT(elementsInSubList) )
  3100. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  3101. else
  3102. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  3103. return -1;
  3104. }
  3105. else
  3106. {
  3107. // Return to caller the amount of elments in this sublist
  3108. elementsInSubList = countElements;
  3109. }
  3110. // The first dword in the buffer will hold the number of elements
  3111. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  3112. // Add the values
  3113. bcInit.AddCode(&ctx.bc);
  3114. }
  3115. else if( patternNode->type == asLPT_TYPE )
  3116. {
  3117. bool isEmpty = false;
  3118. // Determine the size of the element
  3119. asUINT size = 0;
  3120. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  3121. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  3122. {
  3123. asCExprContext lctx(engine);
  3124. asCExprContext rctx(engine);
  3125. if( valueNode->nodeType == snAssignment )
  3126. {
  3127. // Compile the assignment expression
  3128. CompileAssignment(valueNode, &rctx);
  3129. if( dt.GetTokenType() == ttQuestion )
  3130. {
  3131. // Make sure the type is not ambiguous
  3132. DetermineSingleFunc(&rctx, valueNode);
  3133. // We now know the type
  3134. dt = rctx.type.dataType;
  3135. dt.MakeReadOnly(false);
  3136. dt.MakeReference(false);
  3137. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3138. if( bufferSize & 0x3 )
  3139. bufferSize += 4 - (bufferSize & 0x3);
  3140. // When value assignment for reference types us disabled, make sure all ref types are passed in as handles
  3141. if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles())
  3142. dt.MakeHandle(true);
  3143. // Place the type id in the buffer
  3144. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3145. bufferSize += 4;
  3146. }
  3147. }
  3148. else if( valueNode->nodeType == snInitList )
  3149. {
  3150. if( dt.GetTokenType() == ttQuestion )
  3151. {
  3152. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3153. asCString str;
  3154. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3155. Error(str.AddressOf(), valueNode);
  3156. rctx.type.SetDummy();
  3157. dt = rctx.type.dataType;
  3158. }
  3159. else
  3160. {
  3161. // Allocate a temporary variable that will be initialized with the list
  3162. int offset = AllocateVariable(dt, true);
  3163. rctx.type.Set(dt);
  3164. rctx.type.isVariable = true;
  3165. rctx.type.isTemporary = true;
  3166. rctx.type.stackOffset = (short)offset;
  3167. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3168. // Put the object on the stack
  3169. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  3170. // It is a reference that we place on the stack
  3171. rctx.type.dataType.MakeReference(true);
  3172. }
  3173. }
  3174. // Determine size of the element
  3175. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3176. size = dt.GetSizeInMemoryBytes();
  3177. else
  3178. size = AS_PTR_SIZE*4;
  3179. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3180. if( size >= 4 && (bufferSize & 0x3) )
  3181. bufferSize += 4 - (bufferSize & 0x3);
  3182. // Compile the lvalue
  3183. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3184. lctx.type.Set(dt);
  3185. lctx.type.isLValue = true;
  3186. if( dt.IsPrimitive() )
  3187. {
  3188. lctx.bc.Instr(asBC_PopRPtr);
  3189. lctx.type.dataType.MakeReference(true);
  3190. }
  3191. else if( dt.IsObjectHandle() ||
  3192. dt.GetTypeInfo()->flags & asOBJ_REF )
  3193. {
  3194. lctx.type.isExplicitHandle = true;
  3195. lctx.type.dataType.MakeReference(true);
  3196. }
  3197. else
  3198. {
  3199. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3200. // Make sure the object has been constructed before the assignment
  3201. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3202. asSTypeBehaviour *beh = dt.GetBehaviour();
  3203. int func = 0;
  3204. if( beh ) func = beh->construct;
  3205. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3206. {
  3207. asCString str;
  3208. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3209. Error(str, valueNode);
  3210. }
  3211. else if( func )
  3212. {
  3213. // Call the constructor as a normal function
  3214. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3215. asCExprContext ctx(engine);
  3216. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3217. bcInit.AddCode(&ctx.bc);
  3218. }
  3219. }
  3220. if( lctx.type.dataType.IsNullHandle() )
  3221. {
  3222. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3223. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3224. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3225. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3226. }
  3227. else
  3228. {
  3229. asCExprContext ctx(engine);
  3230. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3231. if( !lctx.type.dataType.IsPrimitive() )
  3232. ctx.bc.Instr(asBC_PopPtr);
  3233. // Release temporary variables used by expression
  3234. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3235. ProcessDeferredParams(&ctx);
  3236. bcInit.AddCode(&ctx.bc);
  3237. }
  3238. }
  3239. else
  3240. {
  3241. if( builder->engine->ep.disallowEmptyListElements )
  3242. {
  3243. // Empty elements are not allowed, except if it is the last in the list
  3244. isEmpty = true;
  3245. }
  3246. else
  3247. {
  3248. // There is no specific value so we need to fill it with a default value
  3249. if( dt.GetTokenType() == ttQuestion )
  3250. {
  3251. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3252. if( bufferSize & 0x3 )
  3253. bufferSize += 4 - (bufferSize & 0x3);
  3254. // Place the type id for a null handle in the buffer
  3255. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3256. bufferSize += 4;
  3257. dt = asCDataType::CreateNullHandle();
  3258. // No need to initialize the handle as the buffer is already initialized with zeroes
  3259. }
  3260. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3261. {
  3262. // For value types with default constructor we need to call the constructor
  3263. asSTypeBehaviour *beh = dt.GetBehaviour();
  3264. int func = 0;
  3265. if( beh ) func = beh->construct;
  3266. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3267. {
  3268. asCString str;
  3269. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3270. Error(str, valueNode);
  3271. }
  3272. else if( func )
  3273. {
  3274. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3275. if( bufferSize & 0x3 )
  3276. bufferSize += 4 - (bufferSize & 0x3);
  3277. // Call the constructor as a normal function
  3278. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3279. asCExprContext ctx(engine);
  3280. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3281. bcInit.AddCode(&ctx.bc);
  3282. }
  3283. }
  3284. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3285. {
  3286. // For ref types (not handles) we need to call the default factory
  3287. asSTypeBehaviour *beh = dt.GetBehaviour();
  3288. int func = 0;
  3289. if( beh ) func = beh->factory;
  3290. if( func == 0 )
  3291. {
  3292. asCString str;
  3293. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3294. Error(str, valueNode);
  3295. }
  3296. else if( func )
  3297. {
  3298. asCExprContext rctx(engine);
  3299. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3300. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3301. if( bufferSize & 0x3 )
  3302. bufferSize += 4 - (bufferSize & 0x3);
  3303. asCExprContext lctx(engine);
  3304. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3305. lctx.type.Set(dt);
  3306. lctx.type.isLValue = true;
  3307. lctx.type.isExplicitHandle = true;
  3308. lctx.type.dataType.MakeReference(true);
  3309. asCExprContext ctx(engine);
  3310. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3311. if( !lctx.type.dataType.IsPrimitive() )
  3312. ctx.bc.Instr(asBC_PopPtr);
  3313. // Release temporary variables used by expression
  3314. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3315. ProcessDeferredParams(&ctx);
  3316. bcInit.AddCode(&ctx.bc);
  3317. }
  3318. }
  3319. }
  3320. }
  3321. if( !isEmpty )
  3322. {
  3323. // Determine size of the element
  3324. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3325. size = dt.GetSizeInMemoryBytes();
  3326. else
  3327. size = AS_PTR_SIZE*4;
  3328. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3329. bufferSize += size;
  3330. }
  3331. // Move to the next element
  3332. patternNode = patternNode->next;
  3333. valueNode = valueNode->next;
  3334. if( isEmpty )
  3335. {
  3336. // The caller will determine if the empty element should be ignored or not
  3337. return 1;
  3338. }
  3339. }
  3340. else
  3341. asASSERT( false );
  3342. return 0;
  3343. }
  3344. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3345. {
  3346. // Don't clear the hasReturn flag if this is an empty statement
  3347. // to avoid false errors of 'not all paths return'
  3348. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3349. *hasReturn = false;
  3350. if (statement->nodeType == snStatementBlock)
  3351. CompileStatementBlock(statement, true, hasReturn, bc);
  3352. else if (statement->nodeType == snIf)
  3353. CompileIfStatement(statement, hasReturn, bc);
  3354. else if (statement->nodeType == snFor)
  3355. CompileForStatement(statement, bc);
  3356. else if (statement->nodeType == snWhile)
  3357. CompileWhileStatement(statement, bc);
  3358. else if (statement->nodeType == snDoWhile)
  3359. CompileDoWhileStatement(statement, bc);
  3360. else if (statement->nodeType == snExpressionStatement)
  3361. CompileExpressionStatement(statement, bc);
  3362. else if (statement->nodeType == snBreak)
  3363. CompileBreakStatement(statement, bc);
  3364. else if (statement->nodeType == snContinue)
  3365. CompileContinueStatement(statement, bc);
  3366. else if (statement->nodeType == snSwitch)
  3367. CompileSwitchStatement(statement, hasReturn, bc);
  3368. else if (statement->nodeType == snTryCatch)
  3369. CompileTryCatch(statement, hasReturn, bc);
  3370. else if (statement->nodeType == snReturn)
  3371. {
  3372. CompileReturnStatement(statement, bc);
  3373. *hasReturn = true;
  3374. }
  3375. else
  3376. asASSERT(false);
  3377. }
  3378. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3379. {
  3380. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3381. // Reserve label for break statements
  3382. int breakLabel = nextLabel++;
  3383. breakLabels.PushLast(breakLabel);
  3384. // Add a variable scope that will be used by CompileBreak
  3385. // to know where to stop deallocating variables
  3386. AddVariableScope(true, false);
  3387. //---------------------------
  3388. // Compile the switch expression
  3389. //-------------------------------
  3390. // Compile the switch expression
  3391. asCExprContext expr(engine);
  3392. CompileAssignment(snode->firstChild, &expr);
  3393. // Verify that the expression is a primitive type
  3394. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3395. {
  3396. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3397. return;
  3398. }
  3399. ProcessPropertyGetAccessor(&expr, snode);
  3400. // TODO: Need to support 64bit integers
  3401. // Convert the expression to a 32bit variable
  3402. asCDataType to;
  3403. if( expr.type.dataType.IsIntegerType() )
  3404. to.SetTokenType(ttInt);
  3405. else if( expr.type.dataType.IsUnsignedType() )
  3406. to.SetTokenType(ttUInt);
  3407. // Make sure the value is in a variable
  3408. if( expr.type.dataType.IsReference() )
  3409. ConvertToVariable(&expr);
  3410. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3411. ConvertToVariable(&expr);
  3412. int offset = expr.type.stackOffset;
  3413. ProcessDeferredParams(&expr);
  3414. //-------------------------------
  3415. // Determine case values and labels
  3416. //--------------------------------
  3417. // Remember the first label so that we can later pass the
  3418. // correct label to each CompileCase()
  3419. int firstCaseLabel = nextLabel;
  3420. int defaultLabel = 0;
  3421. asCArray<int> caseValues;
  3422. asCArray<int> caseLabels;
  3423. // Compile all case comparisons and make them jump to the right label
  3424. asCScriptNode *cnode = snode->firstChild->next;
  3425. while( cnode )
  3426. {
  3427. // Each case should have a constant expression
  3428. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3429. {
  3430. // Compile expression
  3431. asCExprContext c(engine);
  3432. CompileExpression(cnode->firstChild, &c);
  3433. // Verify that the result is a constant
  3434. if( !c.type.isConstant )
  3435. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3436. // Verify that the result is an integral number
  3437. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3438. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3439. else
  3440. {
  3441. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3442. // Has this case been declared already?
  3443. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3444. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3445. // TODO: Optimize: We can insert the numbers sorted already
  3446. // Store constant for later use
  3447. caseValues.PushLast(c.type.GetConstantDW());
  3448. // Reserve label for this case
  3449. caseLabels.PushLast(nextLabel++);
  3450. }
  3451. }
  3452. else
  3453. {
  3454. // TODO: It shouldn't be necessary for the default case to be the last one.
  3455. // Is default the last case?
  3456. if( cnode->next )
  3457. {
  3458. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3459. break;
  3460. }
  3461. // Reserve label for this case
  3462. defaultLabel = nextLabel++;
  3463. }
  3464. cnode = cnode->next;
  3465. }
  3466. // check for empty switch
  3467. if (caseValues.GetLength() == 0)
  3468. {
  3469. Error(TXT_EMPTY_SWITCH, snode);
  3470. return;
  3471. }
  3472. if( defaultLabel == 0 )
  3473. defaultLabel = breakLabel;
  3474. //---------------------------------
  3475. // Output the optimized case comparisons
  3476. // with jumps to the case code
  3477. //------------------------------------
  3478. // Sort the case values by increasing value. Do the sort together with the labels
  3479. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3480. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3481. {
  3482. for( int bck = fwd - 1; bck >= 0; bck-- )
  3483. {
  3484. int bckp = bck + 1;
  3485. if( caseValues[bck] > caseValues[bckp] )
  3486. {
  3487. // Swap the values in both arrays
  3488. int swap = caseValues[bckp];
  3489. caseValues[bckp] = caseValues[bck];
  3490. caseValues[bck] = swap;
  3491. swap = caseLabels[bckp];
  3492. caseLabels[bckp] = caseLabels[bck];
  3493. caseLabels[bck] = swap;
  3494. }
  3495. else
  3496. break;
  3497. }
  3498. }
  3499. // Find ranges of consecutive numbers
  3500. asCArray<int> ranges;
  3501. ranges.PushLast(0);
  3502. asUINT n;
  3503. for( n = 1; n < caseValues.GetLength(); ++n )
  3504. {
  3505. // We can join numbers that are less than 5 numbers
  3506. // apart since the output code will still be smaller
  3507. if( caseValues[n] > caseValues[n-1] + 5 )
  3508. ranges.PushLast(n);
  3509. }
  3510. // If the value is larger than the largest case value, jump to default
  3511. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3512. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3513. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3514. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3515. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3516. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3517. // binary search instead of a linear search through the ranges
  3518. // For each range
  3519. int range;
  3520. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3521. {
  3522. // Find the largest value in this range
  3523. int maxRange = caseValues[ranges[range]];
  3524. int index = ranges[range];
  3525. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3526. maxRange = caseValues[index];
  3527. // If there are only 2 numbers then it is better to compare them directly
  3528. if( index - ranges[range] > 2 )
  3529. {
  3530. // If the value is smaller than the smallest case value in the range, jump to default
  3531. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3532. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3533. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3534. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3535. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3536. int nextRangeLabel = nextLabel++;
  3537. // If this is the last range we don't have to make this test
  3538. if( range < (int)ranges.GetLength() - 1 )
  3539. {
  3540. // If the value is larger than the largest case value in the range, jump to the next range
  3541. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3542. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3543. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3544. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3545. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3546. }
  3547. // Jump forward according to the value
  3548. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3549. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3550. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3551. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3552. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3553. // Add the list of jumps to the correct labels (any holes, jump to default)
  3554. index = ranges[range];
  3555. for( int i = caseValues[index]; i <= maxRange; i++ )
  3556. {
  3557. if( caseValues[index] == i )
  3558. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3559. else
  3560. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3561. }
  3562. expr.bc.Label((short)nextRangeLabel);
  3563. }
  3564. else
  3565. {
  3566. // Simply make a comparison with each value
  3567. for( int i = ranges[range]; i < index; ++i )
  3568. {
  3569. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3570. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3571. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3572. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3573. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3574. }
  3575. }
  3576. }
  3577. // Catch any value that falls trough
  3578. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3579. // Release the temporary variable previously stored
  3580. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3581. // TODO: optimize: Should optimize each piece individually
  3582. expr.bc.OptimizeLocally(tempVariableOffsets);
  3583. //----------------------------------
  3584. // Output case implementations
  3585. //----------------------------------
  3586. // Compile case implementations, each one with the label before it
  3587. cnode = snode->firstChild->next;
  3588. while( cnode )
  3589. {
  3590. // Each case should have a constant expression
  3591. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3592. {
  3593. expr.bc.Label((short)firstCaseLabel++);
  3594. CompileCase(cnode->firstChild->next, &expr.bc);
  3595. }
  3596. else
  3597. {
  3598. expr.bc.Label((short)defaultLabel);
  3599. // Is default the last case?
  3600. if( cnode->next )
  3601. {
  3602. // We've already reported this error
  3603. break;
  3604. }
  3605. CompileCase(cnode->firstChild, &expr.bc);
  3606. }
  3607. cnode = cnode->next;
  3608. }
  3609. //--------------------------------
  3610. bc->AddCode(&expr.bc);
  3611. // Add break label
  3612. bc->Label((short)breakLabel);
  3613. breakLabels.PopLast();
  3614. RemoveVariableScope();
  3615. }
  3616. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3617. {
  3618. bool isFinished = false;
  3619. bool hasReturn = false;
  3620. bool hasUnreachableCode = false;
  3621. while( node )
  3622. {
  3623. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3624. {
  3625. hasUnreachableCode = true;
  3626. Warning(TXT_UNREACHABLE_CODE, node);
  3627. break;
  3628. }
  3629. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3630. isFinished = true;
  3631. asCByteCode statement(engine);
  3632. if( node->nodeType == snDeclaration )
  3633. {
  3634. Error(TXT_DECL_IN_SWITCH, node);
  3635. // Compile it anyway to avoid further compiler errors
  3636. CompileDeclaration(node, &statement);
  3637. }
  3638. else
  3639. CompileStatement(node, &hasReturn, &statement);
  3640. LineInstr(bc, node->tokenPos);
  3641. bc->AddCode(&statement);
  3642. if( !hasCompileErrors )
  3643. asASSERT( tempVariables.GetLength() == 0 );
  3644. node = node->next;
  3645. }
  3646. }
  3647. void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc)
  3648. {
  3649. // We will use one label before and another after the catch statement
  3650. int beforeCatchLabel = nextLabel++;
  3651. int afterCatchLabel = nextLabel++;
  3652. // Compile the try block
  3653. bool hasReturnTry;
  3654. asCByteCode tryBC(engine);
  3655. CompileStatement(node->firstChild, &hasReturnTry, &tryBC);
  3656. // Add marker to unwind exception until here, then jump to catch block
  3657. bc->TryBlock((short)beforeCatchLabel);
  3658. // Add the byte code
  3659. LineInstr(bc, node->firstChild->tokenPos);
  3660. bc->AddCode(&tryBC);
  3661. // Add jump to after catch
  3662. bc->InstrINT(asBC_JMP, afterCatchLabel);
  3663. // Compile the catch block
  3664. bool hasReturnCatch;
  3665. asCByteCode catchBC(engine);
  3666. CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC);
  3667. // Add marker to tell bytecode optimizer that this is a catch
  3668. // block so the code is not removed as unreachable code
  3669. bc->Label((short)beforeCatchLabel);
  3670. // Add the byte code
  3671. LineInstr(bc, node->firstChild->next->tokenPos);
  3672. bc->AddCode(&catchBC);
  3673. // Add the label after catch
  3674. bc->Label((short)afterCatchLabel);
  3675. // The try/catch statement only has return (i.e. no code after
  3676. // the try/catch block will be executed) if both blocks have
  3677. *hasReturn = hasReturnTry && hasReturnCatch;
  3678. }
  3679. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3680. {
  3681. // We will use one label for the if statement
  3682. // and possibly another for the else statement
  3683. int afterLabel = nextLabel++;
  3684. // Compile the expression
  3685. asCExprContext expr(engine);
  3686. int r = CompileAssignment(inode->firstChild, &expr);
  3687. if( r == 0 )
  3688. {
  3689. // Allow value types to be converted to bool using 'bool opImplConv()'
  3690. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3691. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3692. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3693. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3694. else
  3695. {
  3696. if( !expr.type.isConstant )
  3697. {
  3698. ProcessPropertyGetAccessor(&expr, inode);
  3699. ConvertToVariable(&expr);
  3700. ProcessDeferredParams(&expr);
  3701. // Add a test
  3702. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3703. expr.bc.Instr(asBC_ClrHi);
  3704. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3705. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3706. expr.bc.OptimizeLocally(tempVariableOffsets);
  3707. bc->AddCode(&expr.bc);
  3708. }
  3709. #if AS_SIZEOF_BOOL == 1
  3710. else if( expr.type.GetConstantB() == 0 )
  3711. #else
  3712. else if (expr.type.GetConstantDW() == 0)
  3713. #endif
  3714. {
  3715. // Jump to the else case
  3716. bc->InstrINT(asBC_JMP, afterLabel);
  3717. // TODO: Should we warn that the expression will always go to the else?
  3718. }
  3719. }
  3720. }
  3721. // Compile the if statement
  3722. bool origIsConstructorCalled = m_isConstructorCalled;
  3723. bool hasReturn1;
  3724. asCByteCode ifBC(engine);
  3725. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3726. // Add the byte code
  3727. LineInstr(bc, inode->firstChild->next->tokenPos);
  3728. bc->AddCode(&ifBC);
  3729. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3730. {
  3731. // Don't allow if( expr );
  3732. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3733. }
  3734. // If one of the statements call the constructor, the other must as well
  3735. // otherwise it is possible the constructor is never called
  3736. bool constructorCall1 = false;
  3737. bool constructorCall2 = false;
  3738. if( !origIsConstructorCalled && m_isConstructorCalled )
  3739. constructorCall1 = true;
  3740. // Do we have an else statement?
  3741. if( inode->firstChild->next != inode->lastChild )
  3742. {
  3743. // Reset the constructor called flag so the else statement can call the constructor too
  3744. m_isConstructorCalled = origIsConstructorCalled;
  3745. int afterElse = 0;
  3746. if( !hasReturn1 )
  3747. {
  3748. afterElse = nextLabel++;
  3749. // Add jump to after the else statement
  3750. bc->InstrINT(asBC_JMP, afterElse);
  3751. }
  3752. // Add label for the else statement
  3753. bc->Label((short)afterLabel);
  3754. bool hasReturn2;
  3755. asCByteCode elseBC(engine);
  3756. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3757. // Add byte code for the else statement
  3758. LineInstr(bc, inode->lastChild->tokenPos);
  3759. bc->AddCode(&elseBC);
  3760. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3761. {
  3762. // Don't allow if( expr ) {} else;
  3763. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3764. }
  3765. if( !hasReturn1 )
  3766. {
  3767. // Add label for the end of else statement
  3768. bc->Label((short)afterElse);
  3769. }
  3770. // The if statement only has return if both alternatives have
  3771. *hasReturn = hasReturn1 && hasReturn2;
  3772. if( !origIsConstructorCalled && m_isConstructorCalled )
  3773. constructorCall2 = true;
  3774. }
  3775. else
  3776. {
  3777. // Add label for the end of if statement
  3778. bc->Label((short)afterLabel);
  3779. *hasReturn = false;
  3780. }
  3781. // Make sure both or neither conditions call a constructor
  3782. if( (constructorCall1 && !constructorCall2) ||
  3783. (constructorCall2 && !constructorCall1) )
  3784. {
  3785. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3786. }
  3787. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3788. }
  3789. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3790. {
  3791. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3792. AddVariableScope(true, true);
  3793. // We will use three labels for the for loop
  3794. int conditionLabel = nextLabel++;
  3795. int afterLabel = nextLabel++;
  3796. int continueLabel = nextLabel++;
  3797. int insideLabel = nextLabel++;
  3798. continueLabels.PushLast(continueLabel);
  3799. breakLabels.PushLast(afterLabel);
  3800. //---------------------------------------
  3801. // Compile the initialization statement
  3802. asCByteCode initBC(engine);
  3803. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3804. if( fnode->firstChild->nodeType == snDeclaration )
  3805. CompileDeclaration(fnode->firstChild, &initBC);
  3806. else
  3807. CompileExpressionStatement(fnode->firstChild, &initBC);
  3808. //-----------------------------------
  3809. // Compile the condition statement
  3810. asCExprContext expr(engine);
  3811. asCScriptNode *second = fnode->firstChild->next;
  3812. if( second->firstChild )
  3813. {
  3814. int r = CompileAssignment(second->firstChild, &expr);
  3815. if( r >= 0 )
  3816. {
  3817. // Allow value types to be converted to bool using 'bool opImplConv()'
  3818. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3819. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3820. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3821. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3822. else
  3823. {
  3824. ProcessPropertyGetAccessor(&expr, second);
  3825. ConvertToVariable(&expr);
  3826. ProcessDeferredParams(&expr);
  3827. // If expression is false exit the loop
  3828. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3829. expr.bc.Instr(asBC_ClrHi);
  3830. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3831. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3832. expr.bc.OptimizeLocally(tempVariableOffsets);
  3833. // Prepend the line instruction for the condition
  3834. asCByteCode tmp(engine);
  3835. LineInstr(&tmp, second->firstChild->tokenPos);
  3836. tmp.AddCode(&expr.bc);
  3837. expr.bc.AddCode(&tmp);
  3838. }
  3839. }
  3840. }
  3841. //---------------------------
  3842. // Compile the increment statement(s)
  3843. asCByteCode nextBC(engine);
  3844. asCScriptNode *cnode = second->next;
  3845. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3846. {
  3847. LineInstr(&nextBC, cnode->tokenPos);
  3848. CompileExpressionStatement(cnode, &nextBC);
  3849. cnode = cnode->next;
  3850. }
  3851. //------------------------------
  3852. // Compile loop statement
  3853. bool hasReturn;
  3854. asCByteCode forBC(engine);
  3855. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3856. //-------------------------------
  3857. // Join the code pieces
  3858. bc->AddCode(&initBC);
  3859. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3860. bc->Label((short)insideLabel);
  3861. // Add a suspend bytecode inside the loop to guarantee
  3862. // that the application can suspend the execution
  3863. bc->Instr(asBC_SUSPEND);
  3864. bc->InstrPTR(asBC_JitEntry, 0);
  3865. LineInstr(bc, fnode->lastChild->tokenPos);
  3866. bc->AddCode(&forBC);
  3867. bc->Label((short)continueLabel);
  3868. bc->AddCode(&nextBC);
  3869. bc->Label((short)conditionLabel);
  3870. if( expr.bc.GetLastInstr() == -1 )
  3871. // There is no condition, so we just always jump
  3872. bc->InstrDWORD(asBC_JMP, insideLabel);
  3873. else
  3874. bc->AddCode(&expr.bc);
  3875. bc->Label((short)afterLabel);
  3876. continueLabels.PopLast();
  3877. breakLabels.PopLast();
  3878. // Deallocate variables in this block, in reverse order
  3879. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3880. {
  3881. sVariable *v = variables->variables[n];
  3882. // Call variable destructors here, for variables not yet destroyed
  3883. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3884. // Don't deallocate function parameters
  3885. if( v->stackOffset > 0 )
  3886. DeallocateVariable(v->stackOffset);
  3887. }
  3888. RemoveVariableScope();
  3889. }
  3890. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3891. {
  3892. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3893. AddVariableScope(true, true);
  3894. // We will use two labels for the while loop
  3895. int beforeLabel = nextLabel++;
  3896. int afterLabel = nextLabel++;
  3897. continueLabels.PushLast(beforeLabel);
  3898. breakLabels.PushLast(afterLabel);
  3899. // Add label before the expression
  3900. bc->Label((short)beforeLabel);
  3901. // Compile expression
  3902. asCExprContext expr(engine);
  3903. int r = CompileAssignment(wnode->firstChild, &expr);
  3904. if( r == 0 )
  3905. {
  3906. // Allow value types to be converted to bool using 'bool opImplConv()'
  3907. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3908. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3909. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3910. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3911. else
  3912. {
  3913. ProcessPropertyGetAccessor(&expr, wnode);
  3914. ConvertToVariable(&expr);
  3915. ProcessDeferredParams(&expr);
  3916. // Jump to end of statement if expression is false
  3917. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3918. expr.bc.Instr(asBC_ClrHi);
  3919. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3920. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3921. expr.bc.OptimizeLocally(tempVariableOffsets);
  3922. bc->AddCode(&expr.bc);
  3923. }
  3924. }
  3925. // Add a suspend bytecode inside the loop to guarantee
  3926. // that the application can suspend the execution
  3927. bc->Instr(asBC_SUSPEND);
  3928. bc->InstrPTR(asBC_JitEntry, 0);
  3929. // Compile statement
  3930. bool hasReturn;
  3931. asCByteCode whileBC(engine);
  3932. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3933. // Add byte code for the statement
  3934. LineInstr(bc, wnode->lastChild->tokenPos);
  3935. bc->AddCode(&whileBC);
  3936. // Jump to the expression
  3937. bc->InstrINT(asBC_JMP, beforeLabel);
  3938. // Add label after the statement
  3939. bc->Label((short)afterLabel);
  3940. continueLabels.PopLast();
  3941. breakLabels.PopLast();
  3942. RemoveVariableScope();
  3943. }
  3944. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3945. {
  3946. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3947. AddVariableScope(true, true);
  3948. // We will use two labels for the while loop
  3949. int beforeLabel = nextLabel++;
  3950. int beforeTest = nextLabel++;
  3951. int afterLabel = nextLabel++;
  3952. continueLabels.PushLast(beforeTest);
  3953. breakLabels.PushLast(afterLabel);
  3954. // Add label before the statement
  3955. bc->Label((short)beforeLabel);
  3956. // Compile statement
  3957. bool hasReturn;
  3958. asCByteCode whileBC(engine);
  3959. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3960. // Add byte code for the statement
  3961. LineInstr(bc, wnode->firstChild->tokenPos);
  3962. bc->AddCode(&whileBC);
  3963. // Add label before the expression
  3964. bc->Label((short)beforeTest);
  3965. // Add a suspend bytecode inside the loop to guarantee
  3966. // that the application can suspend the execution
  3967. bc->Instr(asBC_SUSPEND);
  3968. bc->InstrPTR(asBC_JitEntry, 0);
  3969. // Add a line instruction
  3970. LineInstr(bc, wnode->lastChild->tokenPos);
  3971. // Compile expression
  3972. asCExprContext expr(engine);
  3973. CompileAssignment(wnode->lastChild, &expr);
  3974. // Allow value types to be converted to bool using 'bool opImplConv()'
  3975. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3976. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  3977. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3978. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3979. else
  3980. {
  3981. ProcessPropertyGetAccessor(&expr, wnode);
  3982. ConvertToVariable(&expr);
  3983. ProcessDeferredParams(&expr);
  3984. // Jump to next iteration if expression is true
  3985. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3986. expr.bc.Instr(asBC_ClrHi);
  3987. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3988. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3989. expr.bc.OptimizeLocally(tempVariableOffsets);
  3990. bc->AddCode(&expr.bc);
  3991. }
  3992. // Add label after the statement
  3993. bc->Label((short)afterLabel);
  3994. continueLabels.PopLast();
  3995. breakLabels.PopLast();
  3996. RemoveVariableScope();
  3997. }
  3998. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3999. {
  4000. if( breakLabels.GetLength() == 0 )
  4001. {
  4002. Error(TXT_INVALID_BREAK, node);
  4003. return;
  4004. }
  4005. // Add destructor calls for all variables that will go out of scope
  4006. // Put this clean up in a block to allow exception handler to understand them
  4007. bc->Block(true);
  4008. asCVariableScope *vs = variables;
  4009. while( !vs->isBreakScope )
  4010. {
  4011. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4012. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4013. vs = vs->parent;
  4014. }
  4015. bc->Block(false);
  4016. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  4017. }
  4018. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  4019. {
  4020. if( continueLabels.GetLength() == 0 )
  4021. {
  4022. Error(TXT_INVALID_CONTINUE, node);
  4023. return;
  4024. }
  4025. // Add destructor calls for all variables that will go out of scope
  4026. // Put this clean up in a block to allow exception handler to understand them
  4027. bc->Block(true);
  4028. asCVariableScope *vs = variables;
  4029. while( !vs->isContinueScope )
  4030. {
  4031. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4032. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4033. vs = vs->parent;
  4034. }
  4035. bc->Block(false);
  4036. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  4037. }
  4038. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  4039. {
  4040. if( enode->firstChild )
  4041. {
  4042. // Compile the expression
  4043. asCExprContext expr(engine);
  4044. CompileAssignment(enode->firstChild, &expr);
  4045. // Must not have unused ambiguous names
  4046. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  4047. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  4048. // Must not have unused anonymous functions
  4049. if( expr.IsLambda() )
  4050. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  4051. // If we get here and there is still an unprocessed property
  4052. // accessor, then process it as a get access. Don't call if there is
  4053. // already a compile error, or we might report an error that is not valid
  4054. if( !hasCompileErrors )
  4055. ProcessPropertyGetAccessor(&expr, enode);
  4056. // Pop the value from the stack
  4057. if( !expr.type.dataType.IsPrimitive() )
  4058. expr.bc.Instr(asBC_PopPtr);
  4059. // Release temporary variables used by expression
  4060. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4061. ProcessDeferredParams(&expr);
  4062. expr.bc.OptimizeLocally(tempVariableOffsets);
  4063. bc->AddCode(&expr.bc);
  4064. }
  4065. }
  4066. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  4067. {
  4068. // The input can be either an object or funcdef, either as handle or reference
  4069. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  4070. // If the object already is stored in temporary variable then nothing needs to be done
  4071. // Note, a type can be temporary without being a variable, in which case it is holding off
  4072. // on releasing a previously used object.
  4073. if( ctx->type.isTemporary && ctx->type.isVariable &&
  4074. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  4075. {
  4076. // If the temporary object is currently not a reference
  4077. // the expression needs to be reevaluated to a reference
  4078. if( !ctx->type.dataType.IsReference() )
  4079. {
  4080. ctx->bc.Instr(asBC_PopPtr);
  4081. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4082. ctx->type.dataType.MakeReference(true);
  4083. }
  4084. return;
  4085. }
  4086. // Allocate temporary variable
  4087. asCDataType dt = ctx->type.dataType;
  4088. dt.MakeReference(false);
  4089. dt.MakeReadOnly(false);
  4090. int offset = AllocateVariable(dt, true, forceOnHeap);
  4091. // Objects stored on the stack are not considered references
  4092. dt.MakeReference(IsVariableOnHeap(offset));
  4093. asCExprValue lvalue;
  4094. lvalue.Set(dt);
  4095. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  4096. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4097. bool prevIsTemp = ctx->type.isTemporary;
  4098. int prevStackOffset = ctx->type.stackOffset;
  4099. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  4100. // Release the previous temporary variable if it hasn't already been released
  4101. if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
  4102. ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
  4103. // Push the reference to the temporary variable on the stack
  4104. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4105. ctx->type.Set(dt);
  4106. ctx->type.isTemporary = true;
  4107. ctx->type.stackOffset = (short)offset;
  4108. ctx->type.isVariable = true;
  4109. ctx->type.isExplicitHandle = isExplicitHandle;
  4110. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4111. }
  4112. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  4113. {
  4114. // Get return type and location
  4115. sVariable *v = variables->GetVariable("return");
  4116. // Basic validations
  4117. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  4118. {
  4119. Error(TXT_MUST_RETURN_VALUE, rnode);
  4120. return;
  4121. }
  4122. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  4123. {
  4124. Error(TXT_CANT_RETURN_VALUE, rnode);
  4125. return;
  4126. }
  4127. // Compile the expression
  4128. if( rnode->firstChild )
  4129. {
  4130. // Compile the expression
  4131. asCExprContext expr(engine);
  4132. int r = CompileAssignment(rnode->firstChild, &expr);
  4133. if( r < 0 ) return;
  4134. if( v->type.IsReference() )
  4135. {
  4136. // The expression that gives the reference must not use any of the
  4137. // variables that must be destroyed upon exit, because then it means
  4138. // reference will stay alive while the clean-up is done, which could
  4139. // potentially mean that the reference is invalidated by the clean-up.
  4140. //
  4141. // When the function is returning a reference, the clean-up of the
  4142. // variables must be done before the evaluation of the expression.
  4143. //
  4144. // A reference to a global variable, or a class member for class methods
  4145. // should be allowed to be returned.
  4146. if( !(expr.type.dataType.IsReference() ||
  4147. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  4148. {
  4149. // Clean up the potential deferred parameters
  4150. ProcessDeferredParams(&expr);
  4151. Error(TXT_NOT_VALID_REFERENCE, rnode);
  4152. return;
  4153. }
  4154. // No references to local variables, temporary variables, or parameters
  4155. // are allowed to be returned, since they go out of scope when the function
  4156. // returns. Even reference parameters are disallowed, since it is not possible
  4157. // to know the scope of them. The exception is the 'this' pointer, which
  4158. // is treated by the compiler as a local variable, but isn't really so.
  4159. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  4160. {
  4161. // Clean up the potential deferred parameters
  4162. ProcessDeferredParams(&expr);
  4163. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  4164. return;
  4165. }
  4166. // The type must match exactly as we cannot convert
  4167. // the reference without loosing the original value
  4168. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  4169. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  4170. !expr.type.dataType.IsObjectHandle() &&
  4171. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  4172. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4173. {
  4174. // Clean up the potential deferred parameters
  4175. ProcessDeferredParams(&expr);
  4176. asCString str;
  4177. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4178. Error(str, rnode);
  4179. return;
  4180. }
  4181. // The expression must not have any deferred expressions, because the evaluation
  4182. // of these cannot be done without keeping the reference which is not safe
  4183. if( expr.deferredParams.GetLength() )
  4184. {
  4185. // Clean up the potential deferred parameters
  4186. ProcessDeferredParams(&expr);
  4187. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4188. return;
  4189. }
  4190. // Make sure the expression isn't using any local variables that
  4191. // will need to be cleaned up before the function completes
  4192. asCArray<int> usedVars;
  4193. expr.bc.GetVarsUsed(usedVars);
  4194. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4195. {
  4196. int var = GetVariableSlot(usedVars[n]);
  4197. if( var != -1 )
  4198. {
  4199. asCDataType dt = variableAllocations[var];
  4200. if( dt.IsObject() )
  4201. {
  4202. ProcessDeferredParams(&expr);
  4203. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4204. return;
  4205. }
  4206. }
  4207. }
  4208. // Can't return the reference if could point to a local variable
  4209. if( expr.type.isRefToLocal )
  4210. {
  4211. ProcessDeferredParams(&expr);
  4212. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4213. return;
  4214. }
  4215. // All objects in the function must be cleaned up before the expression
  4216. // is evaluated, otherwise there is a possibility that the cleanup will
  4217. // invalidate the reference.
  4218. // Destroy the local variables before loading
  4219. // the reference into the register. This will
  4220. // be done before the expression is evaluated.
  4221. DestroyVariables(bc);
  4222. // For primitives the reference is already in the register,
  4223. // but for non-primitives the reference is on the stack so we
  4224. // need to load it into the register
  4225. if( !expr.type.dataType.IsPrimitive() )
  4226. {
  4227. if( !expr.type.dataType.IsObjectHandle() &&
  4228. expr.type.dataType.IsReference() )
  4229. expr.bc.Instr(asBC_RDSPtr);
  4230. expr.bc.Instr(asBC_PopRPtr);
  4231. }
  4232. // There are no temporaries to release so we're done
  4233. }
  4234. else // if( !v->type.IsReference() )
  4235. {
  4236. ProcessPropertyGetAccessor(&expr, rnode);
  4237. // Prepare the value for assignment
  4238. IsVariableInitialized(&expr.type, rnode->firstChild);
  4239. if( v->type.IsPrimitive() )
  4240. {
  4241. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4242. // Implicitly convert the value to the return type
  4243. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4244. // Verify that the conversion was successful
  4245. if( expr.type.dataType != v->type )
  4246. {
  4247. asCString str;
  4248. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4249. Error(str, rnode);
  4250. return;
  4251. }
  4252. else
  4253. {
  4254. ConvertToVariable(&expr);
  4255. // Clean up the local variables and process deferred parameters
  4256. DestroyVariables(&expr.bc);
  4257. ProcessDeferredParams(&expr);
  4258. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4259. // Load the variable in the register
  4260. if( v->type.GetSizeOnStackDWords() == 1 )
  4261. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4262. else
  4263. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4264. }
  4265. }
  4266. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4267. {
  4268. // Value types are returned on the stack, in a location
  4269. // that has been reserved by the calling function.
  4270. if( outFunc->DoesReturnOnStack() )
  4271. {
  4272. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4273. // it should be called directly instead of first converting the expression and
  4274. // then copy the value.
  4275. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4276. {
  4277. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4278. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4279. {
  4280. asCString str;
  4281. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4282. Error(str, rnode->firstChild);
  4283. return;
  4284. }
  4285. }
  4286. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4287. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4288. // Clean up the local variables and process deferred parameters
  4289. DestroyVariables(&expr.bc);
  4290. ProcessDeferredParams(&expr);
  4291. }
  4292. else
  4293. {
  4294. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4295. // Prepare the expression to be loaded into the object
  4296. // register. This will place the reference in local variable
  4297. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4298. // Pop the reference to the temporary variable
  4299. expr.bc.Instr(asBC_PopPtr);
  4300. // Clean up the local variables and process deferred parameters
  4301. DestroyVariables(&expr.bc);
  4302. ProcessDeferredParams(&expr);
  4303. // Load the object pointer into the object register
  4304. // LOADOBJ also clears the address in the variable
  4305. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4306. // LOADOBJ cleared the address in the variable so the object will not be freed
  4307. // here, but the temporary variable must still be freed so the slot can be reused
  4308. // By releasing without the bytecode we do just that.
  4309. ReleaseTemporaryVariable(expr.type, 0);
  4310. }
  4311. }
  4312. }
  4313. expr.bc.OptimizeLocally(tempVariableOffsets);
  4314. bc->AddCode(&expr.bc);
  4315. }
  4316. else
  4317. {
  4318. // For functions that don't return anything
  4319. // we just detroy the local variables
  4320. DestroyVariables(bc);
  4321. }
  4322. // Jump to the end of the function
  4323. bc->InstrINT(asBC_JMP, 0);
  4324. }
  4325. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4326. {
  4327. // Call destructor on all variables except for the function parameters
  4328. // Put the clean-up in a block to allow exception handler to understand this
  4329. bc->Block(true);
  4330. asCVariableScope *vs = variables;
  4331. while( vs )
  4332. {
  4333. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4334. if( vs->variables[n]->stackOffset > 0 )
  4335. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4336. vs = vs->parent;
  4337. }
  4338. bc->Block(false);
  4339. }
  4340. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4341. {
  4342. variables = asNEW(asCVariableScope)(variables);
  4343. if( variables == 0 )
  4344. {
  4345. // Out of memory
  4346. return;
  4347. }
  4348. variables->isBreakScope = isBreakScope;
  4349. variables->isContinueScope = isContinueScope;
  4350. }
  4351. void asCCompiler::RemoveVariableScope()
  4352. {
  4353. if( variables )
  4354. {
  4355. asCVariableScope *var = variables;
  4356. variables = variables->parent;
  4357. asDELETE(var,asCVariableScope);
  4358. }
  4359. }
  4360. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4361. {
  4362. asCString str;
  4363. int r = 0, c = 0;
  4364. asASSERT( node );
  4365. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4366. builder->WriteError(script->name, msg, r, c);
  4367. hasCompileErrors = true;
  4368. }
  4369. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4370. {
  4371. asCString str;
  4372. int r = 0, c = 0;
  4373. asASSERT( node );
  4374. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4375. builder->WriteWarning(script->name, msg, r, c);
  4376. }
  4377. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4378. {
  4379. asCString str;
  4380. int r = 0, c = 0;
  4381. asASSERT( node );
  4382. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4383. builder->WriteInfo(script->name, msg, r, c, false);
  4384. }
  4385. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4386. {
  4387. int r = 0, c = 0;
  4388. asASSERT( node );
  4389. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4390. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4391. {
  4392. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4393. if( inType && func->funcType == asFUNC_VIRTUAL )
  4394. func = inType->virtualFunctionTable[func->vfTableIdx];
  4395. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4396. if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE))
  4397. {
  4398. // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user
  4399. for (unsigned int p = 0; p < func->GetParamCount(); p++)
  4400. {
  4401. int typeId = 0;
  4402. func->GetParam(p, &typeId);
  4403. asITypeInfo *ti = engine->GetTypeInfoById(typeId);
  4404. if (ti && (ti->GetFlags() & asOBJ_FUNCDEF))
  4405. {
  4406. asCString msg;
  4407. msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration());
  4408. builder->WriteInfo(script->name, msg.AddressOf(), r, c, false);
  4409. }
  4410. }
  4411. }
  4412. }
  4413. }
  4414. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4415. {
  4416. int l = int(reservedVariables.GetLength());
  4417. ctx->bc.GetVarsUsed(reservedVariables);
  4418. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4419. reservedVariables.SetLength(l);
  4420. return var;
  4421. }
  4422. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference)
  4423. {
  4424. asCDataType t(type);
  4425. t.MakeReference(asReference);
  4426. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4427. t.SetTokenType(ttInt);
  4428. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4429. t.SetTokenType(ttDouble);
  4430. // Only null handles have the token type unrecognized token
  4431. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4432. bool isOnHeap = true;
  4433. if( t.IsPrimitive() ||
  4434. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  4435. {
  4436. // Primitives and value types (unless overridden) are allocated on the stack
  4437. isOnHeap = false;
  4438. }
  4439. // Find a free location with the same type
  4440. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4441. {
  4442. int slot = freeVariables[n];
  4443. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4444. variableIsTemporary[slot] == isTemporary &&
  4445. variableIsOnHeap[slot] == isOnHeap )
  4446. {
  4447. // We can't return by slot, must count variable sizes
  4448. int offset = GetVariableOffset(slot);
  4449. // Verify that it is not in the list of reserved variables
  4450. bool isUsed = false;
  4451. if( reservedVariables.GetLength() )
  4452. isUsed = reservedVariables.Exists(offset);
  4453. if( !isUsed )
  4454. {
  4455. if( n != freeVariables.GetLength() - 1 )
  4456. freeVariables[n] = freeVariables.PopLast();
  4457. else
  4458. freeVariables.PopLast();
  4459. if( isTemporary )
  4460. tempVariables.PushLast(offset);
  4461. return offset;
  4462. }
  4463. }
  4464. }
  4465. variableAllocations.PushLast(t);
  4466. variableIsTemporary.PushLast(isTemporary);
  4467. variableIsOnHeap.PushLast(isOnHeap);
  4468. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4469. if( isTemporary )
  4470. {
  4471. // Add offset to the currently allocated temporary variables
  4472. tempVariables.PushLast(offset);
  4473. // Add offset to all known offsets to temporary variables, whether allocated or not
  4474. tempVariableOffsets.PushLast(offset);
  4475. }
  4476. return offset;
  4477. }
  4478. int asCCompiler::GetVariableOffset(int varIndex)
  4479. {
  4480. // Return offset to the last dword on the stack
  4481. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4482. int varOffset = 1;
  4483. // Skip lower variables
  4484. for( int n = 0; n < varIndex; n++ )
  4485. {
  4486. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4487. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4488. else
  4489. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4490. }
  4491. if( varIndex < (int)variableAllocations.GetLength() )
  4492. {
  4493. // For variables larger than 1 dword the returned offset should be to the last dword
  4494. int size;
  4495. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4496. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4497. else
  4498. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4499. if( size > 1 )
  4500. varOffset += size-1;
  4501. }
  4502. return varOffset;
  4503. }
  4504. int asCCompiler::GetVariableSlot(int offset)
  4505. {
  4506. int varOffset = 1;
  4507. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4508. {
  4509. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4510. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4511. else
  4512. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4513. if( varOffset == offset )
  4514. return n;
  4515. varOffset++;
  4516. }
  4517. return -1;
  4518. }
  4519. bool asCCompiler::IsVariableOnHeap(int offset)
  4520. {
  4521. int varSlot = GetVariableSlot(offset);
  4522. if( varSlot < 0 )
  4523. {
  4524. // This happens for function arguments that are considered as on the heap
  4525. return true;
  4526. }
  4527. return variableIsOnHeap[varSlot];
  4528. }
  4529. void asCCompiler::DeallocateVariable(int offset)
  4530. {
  4531. // Remove temporary variable
  4532. int n;
  4533. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4534. {
  4535. if( offset == tempVariables[n] )
  4536. {
  4537. if( n == (int)tempVariables.GetLength()-1 )
  4538. tempVariables.PopLast();
  4539. else
  4540. tempVariables[n] = tempVariables.PopLast();
  4541. break;
  4542. }
  4543. }
  4544. // Mark the variable slot available for new allocations
  4545. n = GetVariableSlot(offset);
  4546. if( n != -1 )
  4547. {
  4548. freeVariables.PushLast(n);
  4549. return;
  4550. }
  4551. // We might get here if the variable was implicitly declared
  4552. // because it was used before a formal declaration, in this case
  4553. // the offset is 0x7FFF
  4554. asASSERT(offset == 0x7FFF);
  4555. }
  4556. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4557. {
  4558. if( t.isTemporary )
  4559. {
  4560. ReleaseTemporaryVariable(t.stackOffset, bc);
  4561. t.isTemporary = false;
  4562. }
  4563. }
  4564. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4565. {
  4566. asASSERT( tempVariables.Exists(offset) );
  4567. if( bc )
  4568. {
  4569. // We need to call the destructor on the true variable type
  4570. int n = GetVariableSlot(offset);
  4571. asASSERT( n >= 0 );
  4572. if( n >= 0 )
  4573. {
  4574. asCDataType dt = variableAllocations[n];
  4575. bool isOnHeap = variableIsOnHeap[n];
  4576. // Call destructor
  4577. CallDestructor(dt, offset, isOnHeap, bc);
  4578. }
  4579. }
  4580. DeallocateVariable(offset);
  4581. }
  4582. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4583. {
  4584. if( ctx->type.dataType.IsReference() )
  4585. {
  4586. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4587. {
  4588. ctx->type.dataType.MakeReference(false);
  4589. if( generateCode )
  4590. ctx->bc.Instr(asBC_RDSPtr);
  4591. }
  4592. else
  4593. {
  4594. // This should never happen as primitives are treated differently
  4595. asASSERT(false);
  4596. }
  4597. }
  4598. }
  4599. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4600. {
  4601. // No need to check if there is no variable scope
  4602. if( variables == 0 ) return true;
  4603. // Temporary variables are assumed to be initialized
  4604. if( type->isTemporary ) return true;
  4605. // Verify that it is a variable
  4606. if( !type->isVariable ) return true;
  4607. // Find the variable
  4608. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4609. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4610. if( v == 0 ) return true;
  4611. if( v->isInitialized ) return true;
  4612. // Complex types don't need this test
  4613. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4614. // Mark as initialized so that the user will not be bothered again
  4615. v->isInitialized = true;
  4616. // Write warning
  4617. asCString str;
  4618. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4619. Warning(str, node);
  4620. return false;
  4621. }
  4622. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4623. {
  4624. // Check if the variable is initialized (if it indeed is a variable)
  4625. IsVariableInitialized(&ctx->type, node);
  4626. asCDataType to = ctx->type.dataType;
  4627. to.MakeReference(false);
  4628. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4629. ProcessDeferredParams(ctx);
  4630. }
  4631. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4632. {
  4633. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4634. int l = int(reservedVariables.GetLength());
  4635. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4636. ProcessPropertyGetAccessor(rctx, node);
  4637. // Make sure the rvalue is initialized if it is a variable
  4638. IsVariableInitialized(&rctx->type, node);
  4639. if( lvalue->IsPrimitive() )
  4640. {
  4641. if( rctx->type.dataType.IsPrimitive() )
  4642. {
  4643. if( rctx->type.dataType.IsReference() )
  4644. {
  4645. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4646. ConvertToVariableNotIn(rctx, lvalueExpr);
  4647. }
  4648. }
  4649. // Implicitly convert the value to the right type
  4650. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4651. // Check data type
  4652. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4653. {
  4654. asCString str;
  4655. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4656. Error(str, node);
  4657. rctx->type.SetDummy();
  4658. }
  4659. // Make sure the rvalue is a variable
  4660. if( !rctx->type.isVariable )
  4661. ConvertToVariableNotIn(rctx, lvalueExpr);
  4662. }
  4663. else
  4664. {
  4665. asCDataType to = *lvalue;
  4666. to.MakeReference(false);
  4667. // TODO: ImplicitConversion should know to do this by itself
  4668. // First convert to a handle which will do a reference cast
  4669. if( !lvalue->IsObjectHandle() &&
  4670. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4671. to.MakeHandle(true);
  4672. // Don't allow the implicit conversion to create an object
  4673. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4674. if( !lvalue->IsObjectHandle() &&
  4675. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4676. {
  4677. // Then convert to a reference, which will validate the handle
  4678. to.MakeHandle(false);
  4679. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4680. }
  4681. // Check data type
  4682. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4683. {
  4684. asCString str;
  4685. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4686. Error(str, node);
  4687. }
  4688. else
  4689. {
  4690. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4691. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4692. }
  4693. }
  4694. // Unreserve variables
  4695. reservedVariables.SetLength(l);
  4696. }
  4697. bool asCCompiler::IsLValue(asCExprValue &type)
  4698. {
  4699. if( !type.isLValue ) return false;
  4700. if( type.dataType.IsReadOnly() ) return false;
  4701. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4702. return true;
  4703. }
  4704. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4705. {
  4706. if( lvalue->dataType.IsReadOnly() )
  4707. {
  4708. Error(TXT_REF_IS_READ_ONLY, node);
  4709. return -1;
  4710. }
  4711. if( lvalue->dataType.IsPrimitive() )
  4712. {
  4713. if( lvalue->isVariable )
  4714. {
  4715. // Copy the value between the variables directly
  4716. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4717. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4718. else
  4719. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4720. // Mark variable as initialized
  4721. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4722. if( v ) v->isInitialized = true;
  4723. }
  4724. else if( lvalue->dataType.IsReference() )
  4725. {
  4726. // Copy the value of the variable to the reference in the register
  4727. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4728. if( s == 1 )
  4729. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4730. else if( s == 2 )
  4731. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4732. else if( s == 4 )
  4733. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4734. else if( s == 8 )
  4735. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4736. }
  4737. else
  4738. {
  4739. Error(TXT_NOT_VALID_LVALUE, node);
  4740. return -1;
  4741. }
  4742. }
  4743. else if( !lvalue->isExplicitHandle )
  4744. {
  4745. asCExprContext ctx(engine);
  4746. ctx.type = *lvalue;
  4747. Dereference(&ctx, true);
  4748. *lvalue = ctx.type;
  4749. bc->AddCode(&ctx.bc);
  4750. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4751. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4752. {
  4753. asCExprContext res(engine);
  4754. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4755. bc->AddCode(&res.bc);
  4756. *lvalue = res.type;
  4757. }
  4758. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4759. {
  4760. // Call the default copy operator for script classes
  4761. // This is done differently because the default copy operator
  4762. // is registered as returning int&, but in reality it returns
  4763. // a reference to the object.
  4764. // TODO: Avoid this special case by implementing a copystub for
  4765. // script classes that uses the default copy operator
  4766. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4767. bc->Instr(asBC_PshRPtr);
  4768. }
  4769. else
  4770. {
  4771. // Default copy operator
  4772. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4773. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4774. {
  4775. asCString msg;
  4776. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4777. Error(msg, node);
  4778. return -1;
  4779. }
  4780. // Copy larger data types from a reference
  4781. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4782. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4783. }
  4784. }
  4785. else
  4786. {
  4787. // TODO: The object handle can be stored in a variable as well
  4788. if( !lvalue->dataType.IsReference() )
  4789. {
  4790. Error(TXT_NOT_VALID_REFERENCE, node);
  4791. return -1;
  4792. }
  4793. if( lvalue->dataType.IsFuncdef() )
  4794. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4795. else
  4796. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4797. // Mark variable as initialized
  4798. if( variables )
  4799. {
  4800. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4801. if( v ) v->isInitialized = true;
  4802. }
  4803. }
  4804. return 0;
  4805. }
  4806. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4807. {
  4808. bool conversionDone = false;
  4809. asCArray<int> ops;
  4810. // A ref cast must not remove the constness
  4811. bool isConst = ctx->type.dataType.IsObjectConst();
  4812. // Find a suitable opCast or opImplCast method
  4813. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4814. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4815. {
  4816. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4817. if( (isExplicit && func->name == "opCast") ||
  4818. func->name == "opImplCast" )
  4819. {
  4820. // Is the operator for the output type?
  4821. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4822. continue;
  4823. // Can't call a non-const function on a const object
  4824. if( isConst && !func->IsReadOnly() )
  4825. continue;
  4826. ops.PushLast(func->id);
  4827. }
  4828. }
  4829. // Filter the list by constness to remove const methods if there are matching non-const methods
  4830. FilterConst(ops, !isConst);
  4831. // If there is multiple matches, then pick the most appropriate one
  4832. if (ops.GetLength() > 1)
  4833. {
  4834. // This should only happen if an explicit cast is compiled
  4835. // and the type has both the opCast and opImplCast
  4836. asASSERT(isExplicit);
  4837. asASSERT(ops.GetLength() == 2);
  4838. for (asUINT n = 0; n < ops.GetLength(); n++)
  4839. {
  4840. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4841. if (func->name == "opImplCast")
  4842. {
  4843. ops.RemoveIndex(n);
  4844. n--;
  4845. }
  4846. }
  4847. }
  4848. // Should only have one behaviour for each output type
  4849. if( ops.GetLength() == 1 )
  4850. {
  4851. conversionDone = true;
  4852. if( generateCode )
  4853. {
  4854. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4855. // null, we can create a special CALLSYS instruction that checks
  4856. // if the object pointer is null and if so sets the object register
  4857. // to null directly without executing the function.
  4858. //
  4859. // Alternatively I could force the ref cast behaviours be global
  4860. // functions with 1 parameter, even though they should still be
  4861. // registered with RegisterObjectBehaviour()
  4862. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4863. {
  4864. // Add code to avoid calling the cast behaviour if the handle is already null,
  4865. // because that will raise a null pointer exception due to the cast behaviour
  4866. // being a class method, and the this pointer cannot be null.
  4867. if (!ctx->type.isVariable)
  4868. {
  4869. Dereference(ctx, true);
  4870. ConvertToVariable(ctx);
  4871. }
  4872. // The reference on the stack will not be used
  4873. ctx->bc.Instr(asBC_PopPtr);
  4874. // TODO: runtime optimize: should have immediate comparison for null pointer
  4875. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4876. // 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)
  4877. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4878. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4879. DeallocateVariable(offset);
  4880. int afterLabel = nextLabel++;
  4881. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4882. // Call the cast operator
  4883. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4884. ctx->bc.Instr(asBC_RDSPtr);
  4885. ctx->type.dataType.MakeReference(false);
  4886. asCArray<asCExprContext *> args;
  4887. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4888. ctx->bc.Instr(asBC_PopPtr);
  4889. int endLabel = nextLabel++;
  4890. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4891. ctx->bc.Label((short)afterLabel);
  4892. // Make a NULL pointer
  4893. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4894. ctx->bc.Label((short)endLabel);
  4895. // Push the reference to the handle on the stack
  4896. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4897. }
  4898. else
  4899. {
  4900. // Value types cannot be null, so there is no need to check for this.
  4901. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4902. // as those are only expected as registered global properties that cannot
  4903. // be modified anyway.
  4904. // Call the cast operator
  4905. asCArray<asCExprContext *> args;
  4906. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4907. }
  4908. }
  4909. else
  4910. {
  4911. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4912. ctx->type.Set(func->returnType);
  4913. }
  4914. }
  4915. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() )
  4916. {
  4917. // Check for the generic ref cast method: void opCast(?&out)
  4918. // This option only works if the expected type is a handle
  4919. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4920. {
  4921. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4922. if( (isExplicit && func->name == "opCast") ||
  4923. func->name == "opImplCast" )
  4924. {
  4925. // Does the operator take the ?&out parameter?
  4926. if( func->returnType.GetTokenType() != ttVoid ||
  4927. func->parameterTypes.GetLength() != 1 ||
  4928. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4929. func->inOutFlags[0] != asTM_OUTREF )
  4930. continue;
  4931. ops.PushLast(func->id);
  4932. }
  4933. }
  4934. // Filter the list by constness to remove const methods if there are matching non-const methods
  4935. FilterConst(ops, !isConst);
  4936. // If there is multiple matches, then pick the most appropriate one
  4937. if (ops.GetLength() > 1)
  4938. {
  4939. // This should only happen if an explicit cast is compiled
  4940. // and the type has both the opCast and opImplCast
  4941. asASSERT(isExplicit);
  4942. asASSERT(ops.GetLength() == 2);
  4943. for (asUINT n = 0; n < ops.GetLength(); n++)
  4944. {
  4945. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4946. if (func->name == "opImplCast")
  4947. {
  4948. ops.RemoveIndex(n);
  4949. n--;
  4950. }
  4951. }
  4952. }
  4953. if( ops.GetLength() == 1 )
  4954. {
  4955. conversionDone = true;
  4956. if( generateCode )
  4957. {
  4958. int afterLabel = 0;
  4959. bool doNullCheck = false;
  4960. bool releaseTempVariable = false;
  4961. asCExprContext tmp(engine);
  4962. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4963. {
  4964. tmp.bc.AddCode(&ctx->bc);
  4965. tmp.Merge(ctx);
  4966. // Add code to avoid calling the cast behaviour if the handle is already null,
  4967. // because that will raise a null pointer exception due to the cast behaviour
  4968. // being a class method, and the this pointer cannot be null.
  4969. doNullCheck = true;
  4970. if (!ctx->type.isVariable)
  4971. {
  4972. Dereference(&tmp, true);
  4973. ConvertToVariable(&tmp);
  4974. releaseTempVariable = true;
  4975. }
  4976. // The reference on the stack will not be used
  4977. tmp.bc.Instr(asBC_PopPtr);
  4978. // TODO: runtime optimize: should have immediate comparison for null pointer
  4979. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4980. // 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)
  4981. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4982. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  4983. DeallocateVariable(offset);
  4984. afterLabel = nextLabel++;
  4985. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  4986. // Place the object pointer on the stack
  4987. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  4988. }
  4989. // Allocate a temporary variable of the requested handle type
  4990. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  4991. // Pass the reference of that variable to the function as output parameter
  4992. asCDataType toRef(to);
  4993. toRef.MakeReference(true);
  4994. asCArray<asCExprContext *> args;
  4995. asCExprContext arg(engine);
  4996. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4997. // Don't mark the variable as temporary, so it won't be freed too early
  4998. arg.type.SetVariable(toRef, stackOffset, false);
  4999. arg.type.isLValue = true;
  5000. arg.type.isExplicitHandle = true;
  5001. args.PushLast(&arg);
  5002. // Call the behaviour method
  5003. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5004. if (doNullCheck)
  5005. {
  5006. // Add the call after the null check
  5007. tmp.bc.AddCode(&ctx->bc);
  5008. ctx->bc.AddCode(&tmp.bc);
  5009. int endLabel = nextLabel++;
  5010. ctx->bc.InstrINT(asBC_JMP, endLabel);
  5011. ctx->bc.Label((short)afterLabel);
  5012. // Make a NULL pointer
  5013. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  5014. ctx->bc.Label((short)endLabel);
  5015. }
  5016. // If a temporary variable was allocated in the tmp to convert
  5017. // the input expression to a variable, it must be released here
  5018. if (releaseTempVariable && tmp.type.isTemporary)
  5019. ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
  5020. // Use the reference to the variable as the result of the expression
  5021. // Now we can mark the variable as temporary
  5022. ctx->type.SetVariable(toRef, stackOffset, true);
  5023. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5024. }
  5025. else
  5026. {
  5027. // All casts are legal
  5028. ctx->type.Set(to);
  5029. }
  5030. }
  5031. }
  5032. // If the script object didn't implement a matching opCast or opImplCast
  5033. // then check if the desired type is part of the hierarchy
  5034. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  5035. {
  5036. // We need it to be a reference
  5037. if( !ctx->type.dataType.IsReference() )
  5038. {
  5039. asCDataType toRef = ctx->type.dataType;
  5040. toRef.MakeReference(true);
  5041. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  5042. }
  5043. if( isExplicit )
  5044. {
  5045. // Allow dynamic cast between object handles (only for script objects).
  5046. // At run time this may result in a null handle,
  5047. // which when used will throw an exception
  5048. conversionDone = true;
  5049. if( generateCode )
  5050. {
  5051. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  5052. // Allocate a temporary variable for the returned object
  5053. int returnOffset = AllocateVariable(to, true);
  5054. // Move the pointer from the object register to the temporary variable
  5055. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  5056. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  5057. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5058. ctx->type.SetVariable(to, returnOffset, true);
  5059. ctx->type.dataType.MakeReference(true);
  5060. }
  5061. else
  5062. {
  5063. ctx->type.dataType = to;
  5064. ctx->type.dataType.MakeReference(true);
  5065. }
  5066. }
  5067. else
  5068. {
  5069. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  5070. {
  5071. conversionDone = true;
  5072. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5073. }
  5074. }
  5075. // A ref cast must not remove the constness
  5076. if( isConst )
  5077. ctx->type.dataType.MakeHandleToConst(true);
  5078. }
  5079. return conversionDone;
  5080. }
  5081. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5082. {
  5083. asCDataType to = toOrig;
  5084. to.MakeReference(false);
  5085. asASSERT( !ctx->type.dataType.IsReference() );
  5086. // Maybe no conversion is needed
  5087. if( to.IsEqualExceptConst(ctx->type.dataType) )
  5088. {
  5089. // A primitive is const or not
  5090. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5091. return asCC_NO_CONV;
  5092. }
  5093. // Is the conversion an ambiguous enum value?
  5094. if( ctx->enumValue != "" )
  5095. {
  5096. if( to.IsEnumType() )
  5097. {
  5098. // Attempt to resolve an ambiguous enum value
  5099. asCDataType out;
  5100. asDWORD value;
  5101. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  5102. {
  5103. ctx->type.SetConstantDW(out, value);
  5104. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5105. // Reset the enum value since we no longer need it
  5106. ctx->enumValue = "";
  5107. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  5108. return asCC_NO_CONV;
  5109. }
  5110. }
  5111. // The enum value is ambiguous
  5112. if( node && generateCode )
  5113. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  5114. // Set a dummy to allow the compiler to try to continue the conversion
  5115. ctx->type.SetDummy();
  5116. }
  5117. // Determine the cost of this conversion
  5118. asUINT cost = asCC_NO_CONV;
  5119. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5120. cost = asCC_INT_FLOAT_CONV;
  5121. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  5122. cost = asCC_INT_FLOAT_CONV;
  5123. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  5124. cost = asCC_ENUM_SAME_SIZE_CONV;
  5125. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  5126. cost = asCC_ENUM_DIFF_SIZE_CONV;
  5127. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  5128. cost = asCC_SIGNED_CONV;
  5129. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  5130. cost = asCC_SIGNED_CONV;
  5131. else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
  5132. cost = asCC_PRIMITIVE_SIZE_CONV;
  5133. // Start by implicitly converting constant values
  5134. if( ctx->type.isConstant )
  5135. {
  5136. ImplicitConversionConstant(ctx, to, node, convType);
  5137. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5138. return cost;
  5139. }
  5140. // Allow implicit conversion between numbers
  5141. if( generateCode )
  5142. {
  5143. // When generating the code the decision has already been made, so we don't bother determining the cost
  5144. // Convert smaller types to 32bit first
  5145. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  5146. if( s < 4 )
  5147. {
  5148. ConvertToTempVariable(ctx);
  5149. if( ctx->type.dataType.IsIntegerType() )
  5150. {
  5151. if( s == 1 )
  5152. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  5153. else if( s == 2 )
  5154. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  5155. ctx->type.dataType.SetTokenType(ttInt);
  5156. }
  5157. else if( ctx->type.dataType.IsUnsignedType() )
  5158. {
  5159. if( s == 1 )
  5160. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  5161. else if( s == 2 )
  5162. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  5163. ctx->type.dataType.SetTokenType(ttUInt);
  5164. }
  5165. }
  5166. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5167. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5168. {
  5169. if( ctx->type.dataType.IsIntegerType() ||
  5170. ctx->type.dataType.IsUnsignedType() )
  5171. {
  5172. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5173. {
  5174. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5175. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5176. }
  5177. else
  5178. {
  5179. ConvertToTempVariable(ctx);
  5180. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5181. int offset = AllocateVariable(to, true);
  5182. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5183. ctx->type.SetVariable(to, offset, true);
  5184. }
  5185. }
  5186. else if( ctx->type.dataType.IsFloatType() )
  5187. {
  5188. ConvertToTempVariable(ctx);
  5189. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  5190. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5191. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5192. if( convType != asIC_EXPLICIT_VAL_CAST )
  5193. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5194. }
  5195. else if( ctx->type.dataType.IsDoubleType() )
  5196. {
  5197. ConvertToTempVariable(ctx);
  5198. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5199. int offset = AllocateVariable(to, true);
  5200. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  5201. ctx->type.SetVariable(to, offset, true);
  5202. if( convType != asIC_EXPLICIT_VAL_CAST )
  5203. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5204. }
  5205. // Convert to smaller integer if necessary
  5206. s = to.GetSizeInMemoryBytes();
  5207. if( s < 4 )
  5208. {
  5209. ConvertToTempVariable(ctx);
  5210. if( s == 1 )
  5211. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5212. else if( s == 2 )
  5213. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5214. }
  5215. }
  5216. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5217. {
  5218. if( ctx->type.dataType.IsIntegerType() ||
  5219. ctx->type.dataType.IsUnsignedType() )
  5220. {
  5221. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5222. {
  5223. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5224. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5225. }
  5226. else
  5227. {
  5228. ConvertToTempVariable(ctx);
  5229. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5230. int offset = AllocateVariable(to, true);
  5231. if( ctx->type.dataType.IsUnsignedType() )
  5232. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5233. else
  5234. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5235. ctx->type.SetVariable(to, offset, true);
  5236. }
  5237. }
  5238. else if( ctx->type.dataType.IsFloatType() )
  5239. {
  5240. ConvertToTempVariable(ctx);
  5241. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5242. int offset = AllocateVariable(to, true);
  5243. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5244. ctx->type.SetVariable(to, offset, true);
  5245. if( convType != asIC_EXPLICIT_VAL_CAST )
  5246. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5247. }
  5248. else if( ctx->type.dataType.IsDoubleType() )
  5249. {
  5250. ConvertToTempVariable(ctx);
  5251. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  5252. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5253. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5254. if( convType != asIC_EXPLICIT_VAL_CAST )
  5255. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5256. }
  5257. }
  5258. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5259. {
  5260. if( ctx->type.dataType.IsIntegerType() ||
  5261. ctx->type.dataType.IsUnsignedType() )
  5262. {
  5263. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5264. {
  5265. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5266. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5267. }
  5268. else
  5269. {
  5270. ConvertToTempVariable(ctx);
  5271. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5272. int offset = AllocateVariable(to, true);
  5273. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5274. ctx->type.SetVariable(to, offset, true);
  5275. }
  5276. }
  5277. else if( ctx->type.dataType.IsFloatType() )
  5278. {
  5279. ConvertToTempVariable(ctx);
  5280. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  5281. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5282. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5283. if( convType != asIC_EXPLICIT_VAL_CAST )
  5284. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5285. }
  5286. else if( ctx->type.dataType.IsDoubleType() )
  5287. {
  5288. ConvertToTempVariable(ctx);
  5289. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5290. int offset = AllocateVariable(to, true);
  5291. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5292. ctx->type.SetVariable(to, offset, true);
  5293. if( convType != asIC_EXPLICIT_VAL_CAST )
  5294. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5295. }
  5296. // Convert to smaller integer if necessary
  5297. s = to.GetSizeInMemoryBytes();
  5298. if( s < 4 )
  5299. {
  5300. ConvertToTempVariable(ctx);
  5301. if( s == 1 )
  5302. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5303. else if( s == 2 )
  5304. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5305. }
  5306. }
  5307. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5308. {
  5309. if( ctx->type.dataType.IsIntegerType() ||
  5310. ctx->type.dataType.IsUnsignedType() )
  5311. {
  5312. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5313. {
  5314. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5315. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5316. }
  5317. else
  5318. {
  5319. ConvertToTempVariable(ctx);
  5320. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5321. int offset = AllocateVariable(to, true);
  5322. if( ctx->type.dataType.IsUnsignedType() )
  5323. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5324. else
  5325. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5326. ctx->type.SetVariable(to, offset, true);
  5327. }
  5328. }
  5329. else if( ctx->type.dataType.IsFloatType() )
  5330. {
  5331. ConvertToTempVariable(ctx);
  5332. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5333. int offset = AllocateVariable(to, true);
  5334. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5335. ctx->type.SetVariable(to, offset, true);
  5336. if( convType != asIC_EXPLICIT_VAL_CAST )
  5337. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5338. }
  5339. else if( ctx->type.dataType.IsDoubleType() )
  5340. {
  5341. ConvertToTempVariable(ctx);
  5342. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  5343. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5344. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5345. if( convType != asIC_EXPLICIT_VAL_CAST )
  5346. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5347. }
  5348. }
  5349. else if( to.IsFloatType() )
  5350. {
  5351. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5352. {
  5353. ConvertToTempVariable(ctx);
  5354. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5355. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5356. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5357. }
  5358. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5359. {
  5360. ConvertToTempVariable(ctx);
  5361. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5362. int offset = AllocateVariable(to, true);
  5363. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5364. ctx->type.SetVariable(to, offset, true);
  5365. }
  5366. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5367. {
  5368. ConvertToTempVariable(ctx);
  5369. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5370. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5371. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5372. }
  5373. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5374. {
  5375. ConvertToTempVariable(ctx);
  5376. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5377. int offset = AllocateVariable(to, true);
  5378. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5379. ctx->type.SetVariable(to, offset, true);
  5380. }
  5381. else if( ctx->type.dataType.IsDoubleType() )
  5382. {
  5383. ConvertToTempVariable(ctx);
  5384. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5385. int offset = AllocateVariable(to, true);
  5386. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5387. ctx->type.SetVariable(to, offset, true);
  5388. }
  5389. }
  5390. else if( to.IsDoubleType() )
  5391. {
  5392. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5393. {
  5394. ConvertToTempVariable(ctx);
  5395. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5396. int offset = AllocateVariable(to, true);
  5397. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5398. ctx->type.SetVariable(to, offset, true);
  5399. }
  5400. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5401. {
  5402. ConvertToTempVariable(ctx);
  5403. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5404. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5405. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5406. }
  5407. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5408. {
  5409. ConvertToTempVariable(ctx);
  5410. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5411. int offset = AllocateVariable(to, true);
  5412. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5413. ctx->type.SetVariable(to, offset, true);
  5414. }
  5415. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5416. {
  5417. ConvertToTempVariable(ctx);
  5418. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5419. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5420. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  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_fTOd, offset, ctx->type.stackOffset);
  5428. ctx->type.SetVariable(to, offset, true);
  5429. }
  5430. }
  5431. }
  5432. else
  5433. {
  5434. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5435. to.IsFloatType() || to.IsDoubleType() ||
  5436. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5437. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5438. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5439. {
  5440. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5441. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5442. }
  5443. }
  5444. // Primitive types on the stack, can be const or non-const
  5445. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5446. return cost;
  5447. }
  5448. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5449. {
  5450. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5451. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5452. // Check that the lambda has the correct amount of arguments
  5453. asUINT count = 0;
  5454. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5455. while( argNode->nodeType != snStatementBlock )
  5456. {
  5457. // Check if the specified parameter types match the funcdef
  5458. if (argNode->nodeType == snDataType)
  5459. {
  5460. asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType);
  5461. asETypeModifiers inOutFlag;
  5462. dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
  5463. if (count >= funcDef->parameterTypes.GetLength() ||
  5464. funcDef->parameterTypes[count] != dt ||
  5465. funcDef->inOutFlags[count] != inOutFlag)
  5466. return asCC_NO_CONV;
  5467. argNode = argNode->next;
  5468. }
  5469. if( argNode->nodeType == snIdentifier )
  5470. count++;
  5471. argNode = argNode->next;
  5472. }
  5473. if (funcDef->parameterTypes.GetLength() != count)
  5474. return asCC_NO_CONV;
  5475. asASSERT(argNode->nodeType == snStatementBlock);
  5476. // The Lambda can be used as this funcdef
  5477. ctx->type.dataType = to;
  5478. if( generateCode )
  5479. {
  5480. // Build a unique name for the anonymous function
  5481. asCString name;
  5482. if( m_globalVar )
  5483. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5484. else
  5485. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5486. // Register the lambda with the builder for later compilation
  5487. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace);
  5488. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5489. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5490. // Clear the expression node as it is no longer valid
  5491. ctx->exprNode = 0;
  5492. }
  5493. return asCC_CONST_CONV;
  5494. }
  5495. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5496. {
  5497. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5498. ctx->type.dataType.IsNullHandle() ||
  5499. ctx->IsAnonymousInitList() );
  5500. if( to.IsFuncdef() && ctx->IsLambda() )
  5501. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5502. if (ctx->IsAnonymousInitList())
  5503. {
  5504. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5505. {
  5506. if (generateCode)
  5507. CompileAnonymousInitList(ctx->exprNode, ctx, to);
  5508. else
  5509. ctx->type.dataType = to;
  5510. }
  5511. return asCC_NO_CONV;
  5512. }
  5513. // No conversion from void to any other type
  5514. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5515. return asCC_NO_CONV;
  5516. // No conversion from class method to any type (it requires delegate)
  5517. if( ctx->IsClassMethod() )
  5518. return asCC_NO_CONV;
  5519. // Do we want a var type?
  5520. if( to.GetTokenType() == ttQuestion )
  5521. {
  5522. // Any type can be converted to a var type, but only when not generating code
  5523. asASSERT( !generateCode );
  5524. ctx->type.dataType = to;
  5525. return asCC_VARIABLE_CONV;
  5526. }
  5527. // Do we want a primitive?
  5528. else if( to.IsPrimitive() )
  5529. {
  5530. if( !ctx->type.dataType.IsPrimitive() )
  5531. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5532. else
  5533. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5534. }
  5535. else // The target is a complex type
  5536. {
  5537. if( ctx->type.dataType.IsPrimitive() )
  5538. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5539. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5540. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5541. }
  5542. return asCC_NO_CONV;
  5543. }
  5544. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5545. {
  5546. if( ctx->type.isExplicitHandle )
  5547. {
  5548. // An explicit handle cannot be converted to a primitive
  5549. if( convType != asIC_IMPLICIT_CONV && node )
  5550. {
  5551. asCString str;
  5552. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5553. Error(str, node);
  5554. }
  5555. return asCC_NO_CONV;
  5556. }
  5557. // Find matching value cast behaviours
  5558. // Here we're only interested in those that convert the type to a primitive type
  5559. asCArray<int> funcs;
  5560. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5561. if( ot == 0 )
  5562. {
  5563. if( convType != asIC_IMPLICIT_CONV && node )
  5564. {
  5565. asCString str;
  5566. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5567. Error(str, node);
  5568. }
  5569. return asCC_NO_CONV;
  5570. }
  5571. if( convType == asIC_EXPLICIT_VAL_CAST )
  5572. {
  5573. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5574. {
  5575. // accept both implicit and explicit cast
  5576. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5577. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5578. mthd->parameterTypes.GetLength() == 0 &&
  5579. mthd->returnType.IsPrimitive() )
  5580. funcs.PushLast(ot->methods[n]);
  5581. }
  5582. }
  5583. else
  5584. {
  5585. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5586. {
  5587. // accept only implicit cast
  5588. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5589. if( mthd->name == "opImplConv" &&
  5590. mthd->parameterTypes.GetLength() == 0 &&
  5591. mthd->returnType.IsPrimitive() )
  5592. funcs.PushLast(ot->methods[n]);
  5593. }
  5594. }
  5595. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5596. int funcId = 0;
  5597. if( to.IsMathType() )
  5598. {
  5599. // This matrix describes the priorities of the types to search for, for each target type
  5600. // The first column is the target type, the priorities goes from left to right
  5601. eTokenType matchMtx[10][10] =
  5602. {
  5603. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5604. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5605. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5606. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5607. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5608. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5609. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5610. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5611. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5612. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5613. };
  5614. // Which row to use?
  5615. eTokenType *row = 0;
  5616. for( unsigned int type = 0; type < 10; type++ )
  5617. {
  5618. if( to.GetTokenType() == matchMtx[type][0] )
  5619. {
  5620. row = &matchMtx[type][0];
  5621. break;
  5622. }
  5623. }
  5624. // Find the best matching cast operator
  5625. if( row )
  5626. {
  5627. asCDataType target(to);
  5628. // Priority goes from left to right in the matrix
  5629. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5630. {
  5631. target.SetTokenType(row[attempt]);
  5632. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5633. {
  5634. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5635. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5636. {
  5637. funcId = funcs[n];
  5638. break;
  5639. }
  5640. }
  5641. }
  5642. }
  5643. }
  5644. else
  5645. {
  5646. // Only accept the exact conversion for non-math types
  5647. // Find the matching cast operator
  5648. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5649. {
  5650. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5651. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5652. {
  5653. funcId = funcs[n];
  5654. break;
  5655. }
  5656. }
  5657. }
  5658. // Did we find a suitable function?
  5659. if( funcId != 0 )
  5660. {
  5661. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5662. if( generateCode )
  5663. {
  5664. Dereference(ctx, true);
  5665. PerformFunctionCall(funcId, ctx);
  5666. }
  5667. else
  5668. ctx->type.Set(descr->returnType);
  5669. // Allow one more implicit conversion to another primitive type
  5670. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5671. }
  5672. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5673. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5674. funcs.SetLength(0);
  5675. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5676. {
  5677. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5678. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5679. func->name == "opImplConv" )
  5680. {
  5681. // Does the operator take the ?&out parameter?
  5682. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5683. func->parameterTypes.GetLength() != 1 ||
  5684. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5685. func->inOutFlags[0] != asTM_OUTREF )
  5686. continue;
  5687. funcs.PushLast(ot->methods[n]);
  5688. }
  5689. }
  5690. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5691. // If there are multiple valid value casts, then we must choose the most appropriate one
  5692. if (funcs.GetLength() > 1)
  5693. {
  5694. // This should only happen in case of explicit value cast and
  5695. // the application has registered both opImplConv and opConv
  5696. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5697. asASSERT(funcs.GetLength() == 2);
  5698. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5699. {
  5700. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5701. if (func->name == "opImplConv")
  5702. {
  5703. funcs.RemoveIndex(n);
  5704. n--;
  5705. }
  5706. }
  5707. }
  5708. if( funcs.GetLength() == 1 )
  5709. {
  5710. if( generateCode )
  5711. {
  5712. // Allocate a temporary variable of the requested type
  5713. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5714. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5715. // Pass the reference of that variable to the function as output parameter
  5716. asCDataType toRef(to);
  5717. toRef.MakeReference(true);
  5718. toRef.MakeReadOnly(false);
  5719. asCArray<asCExprContext *> args;
  5720. asCExprContext arg(engine);
  5721. // Don't mark the variable as temporary, so it won't be freed too early
  5722. arg.type.SetVariable(toRef, stackOffset, false);
  5723. arg.type.isLValue = true;
  5724. arg.exprNode = node;
  5725. args.PushLast(&arg);
  5726. // Call the behaviour method
  5727. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5728. // Use the reference to the variable as the result of the expression
  5729. // Now we can mark the variable as temporary
  5730. toRef.MakeReference(false);
  5731. ctx->type.SetVariable(toRef, stackOffset, true);
  5732. }
  5733. else
  5734. ctx->type.Set(to);
  5735. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5736. }
  5737. if( convType != asIC_IMPLICIT_CONV && node )
  5738. {
  5739. asCString str;
  5740. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5741. Error(str, node);
  5742. }
  5743. return asCC_NO_CONV;
  5744. }
  5745. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5746. {
  5747. // Convert null to any object type handle, but not to a non-handle type
  5748. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5749. {
  5750. if( to.IsObjectHandle() )
  5751. {
  5752. ctx->type.dataType = to;
  5753. return asCC_REF_CONV;
  5754. }
  5755. return asCC_NO_CONV;
  5756. }
  5757. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5758. // First attempt to convert the base type without instantiating another instance
  5759. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5760. {
  5761. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5762. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5763. {
  5764. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5765. return asCC_REF_CONV;
  5766. }
  5767. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5768. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5769. {
  5770. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5771. return asCC_REF_CONV;
  5772. }
  5773. // If the types are not equal yet, then we may still be able to find a reference cast
  5774. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5775. {
  5776. // We may still be able to find an implicit ref cast behaviour
  5777. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5778. // Was the conversion done?
  5779. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5780. return asCC_REF_CONV;
  5781. }
  5782. }
  5783. // Convert matching function types
  5784. if( to.IsFuncdef() )
  5785. {
  5786. // If the input expression is already a funcdef, check if it can be converted
  5787. if( ctx->type.dataType.IsFuncdef() &&
  5788. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5789. {
  5790. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5791. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5792. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5793. {
  5794. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5795. return asCC_REF_CONV;
  5796. }
  5797. }
  5798. // If the input expression is a deferred function ref, check if there is a matching func
  5799. if( ctx->methodName != "" )
  5800. {
  5801. // Determine the namespace
  5802. asSNameSpace *ns = 0;
  5803. asCString name = "";
  5804. int pos = ctx->methodName.FindLast("::");
  5805. if( pos >= 0 )
  5806. {
  5807. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5808. // Trim off the last ::
  5809. if( nsName.GetLength() > 2 )
  5810. nsName.SetLength(nsName.GetLength()-2);
  5811. ns = DetermineNameSpace(nsName);
  5812. name = ctx->methodName.SubString(pos+2);
  5813. }
  5814. else
  5815. {
  5816. DetermineNameSpace("");
  5817. name = ctx->methodName;
  5818. }
  5819. asCArray<int> funcs;
  5820. if( ns )
  5821. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5822. // Check if any of the functions have perfect match
  5823. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5824. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5825. {
  5826. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5827. if( toFunc->IsSignatureExceptNameEqual(func) )
  5828. {
  5829. if( generateCode )
  5830. {
  5831. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5832. // Make sure the identified function is shared if we're compiling a shared function
  5833. if( !func->IsShared() && outFunc->IsShared() )
  5834. {
  5835. asCString msg;
  5836. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5837. Error(msg, node);
  5838. }
  5839. }
  5840. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5841. return asCC_REF_CONV;
  5842. }
  5843. }
  5844. }
  5845. }
  5846. return asCC_NO_CONV;
  5847. }
  5848. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5849. {
  5850. asUINT cost = asCC_NO_CONV;
  5851. // If the base type is still different, and we are allowed to instance
  5852. // another object then we can try an implicit value cast
  5853. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5854. {
  5855. // TODO: Implement support for implicit constructor/factory
  5856. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5857. if( ot == 0 )
  5858. return cost;
  5859. asCArray<int> funcs;
  5860. if( convType == asIC_EXPLICIT_VAL_CAST )
  5861. {
  5862. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5863. {
  5864. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5865. // accept both implicit and explicit cast
  5866. if( (func->name == "opConv" ||
  5867. func->name == "opImplConv") &&
  5868. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5869. func->parameterTypes.GetLength() == 0 )
  5870. funcs.PushLast(ot->methods[n]);
  5871. }
  5872. }
  5873. else
  5874. {
  5875. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5876. {
  5877. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5878. // accept only implicit cast
  5879. if( func->name == "opImplConv" &&
  5880. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5881. func->parameterTypes.GetLength() == 0 )
  5882. funcs.PushLast(ot->methods[n]);
  5883. }
  5884. }
  5885. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5886. // If there are multiple valid value casts, then we must choose the most appropriate one
  5887. if (funcs.GetLength() > 1)
  5888. {
  5889. // This should only happen in case of explicit value cast and
  5890. // the application has registered both opImplConv and opConv
  5891. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5892. asASSERT(funcs.GetLength() == 2);
  5893. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5894. {
  5895. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5896. if (func->name == "opImplConv")
  5897. {
  5898. funcs.RemoveIndex(n);
  5899. n--;
  5900. }
  5901. }
  5902. }
  5903. if( funcs.GetLength() == 1 )
  5904. {
  5905. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5906. if( generateCode )
  5907. {
  5908. Dereference(ctx, true);
  5909. bool useVariable = false;
  5910. int stackOffset = 0;
  5911. if( f->DoesReturnOnStack() )
  5912. {
  5913. useVariable = true;
  5914. stackOffset = AllocateVariable(f->returnType, true);
  5915. // Push the pointer to the pre-allocated space for the return value
  5916. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5917. // The object pointer is already on the stack, but should be the top
  5918. // one, so we need to swap the pointers in order to get the correct
  5919. ctx->bc.Instr(asBC_SwapPtr);
  5920. }
  5921. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5922. }
  5923. else
  5924. ctx->type.Set(f->returnType);
  5925. cost = asCC_TO_OBJECT_CONV;
  5926. }
  5927. else
  5928. {
  5929. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5930. // Look for a value cast with variable type
  5931. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5932. {
  5933. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5934. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5935. func->name == "opImplConv" )
  5936. {
  5937. // Does the operator take the ?&out parameter?
  5938. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5939. func->parameterTypes.GetLength() != 1 ||
  5940. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5941. func->inOutFlags[0] != asTM_OUTREF )
  5942. continue;
  5943. funcs.PushLast(ot->methods[n]);
  5944. }
  5945. }
  5946. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5947. // If there are multiple valid value casts, then we must choose the most appropriate one
  5948. if (funcs.GetLength() > 1)
  5949. {
  5950. // This should only happen in case of explicit value cast and
  5951. // the application has registered both opImplConv and opConv
  5952. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5953. asASSERT(funcs.GetLength() == 2);
  5954. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5955. {
  5956. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5957. if (func->name == "opImplConv")
  5958. {
  5959. funcs.RemoveIndex(n);
  5960. n--;
  5961. }
  5962. }
  5963. }
  5964. if( funcs.GetLength() == 1 )
  5965. {
  5966. cost = asCC_TO_OBJECT_CONV;
  5967. if( generateCode )
  5968. {
  5969. // Allocate a temporary variable of the requested type
  5970. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5971. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5972. // Pass the reference of that variable to the function as output parameter
  5973. asCDataType toRef(to);
  5974. toRef.MakeReference(false);
  5975. asCExprContext arg(engine);
  5976. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5977. // If this an object on the heap, the pointer must be dereferenced
  5978. if( IsVariableOnHeap(stackOffset) )
  5979. arg.bc.Instr(asBC_RDSPtr);
  5980. // Don't mark the variable as temporary, so it won't be freed too early
  5981. arg.type.SetVariable(toRef, stackOffset, false);
  5982. arg.type.isLValue = true;
  5983. arg.exprNode = node;
  5984. // Mark the argument as clean, so that MakeFunctionCall knows it
  5985. // doesn't have to make a copy of it in order to protect the value
  5986. arg.isCleanArg = true;
  5987. // Call the behaviour method
  5988. asCArray<asCExprContext *> args;
  5989. args.PushLast(&arg);
  5990. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5991. // Use the reference to the variable as the result of the expression
  5992. // Now we can mark the variable as temporary
  5993. ctx->type.SetVariable(toRef, stackOffset, true);
  5994. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5995. }
  5996. else
  5997. {
  5998. // All casts are legal
  5999. ctx->type.Set(to);
  6000. }
  6001. }
  6002. else if( CastToObjectType(to.GetTypeInfo()) )
  6003. {
  6004. // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type
  6005. if( to.GetTypeInfo()->flags & asOBJ_REF )
  6006. funcs = CastToObjectType(to.GetTypeInfo())->beh.factories;
  6007. else
  6008. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6009. // If not explicit cast, remove any explicit conversion constructors
  6010. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6011. {
  6012. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6013. if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) )
  6014. funcs.RemoveIndex(n--);
  6015. }
  6016. asCArray<asCExprContext *> args;
  6017. args.PushLast(ctx);
  6018. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6019. // Did we find a matching constructor?
  6020. if (funcs.GetLength() == 1)
  6021. {
  6022. if (generateCode)
  6023. {
  6024. // TODO: This should really reuse the code from CompileConstructCall
  6025. // Allocate the new object
  6026. asCExprValue tempObj;
  6027. asCExprContext e(engine);
  6028. bool onHeap = false;
  6029. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6030. {
  6031. tempObj.dataType = to;
  6032. tempObj.dataType.MakeReference(false);
  6033. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6034. tempObj.dataType.MakeReference(true);
  6035. tempObj.isTemporary = true;
  6036. tempObj.isVariable = true;
  6037. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6038. // Push the address of the object on the stack
  6039. if (onHeap)
  6040. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6041. }
  6042. PrepareFunctionCall(funcs[0], &e.bc, args);
  6043. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6044. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6045. {
  6046. // If the object is allocated on the stack, then call the constructor as a normal function
  6047. if (onHeap)
  6048. {
  6049. int offset = 0;
  6050. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6051. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6052. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6053. }
  6054. else
  6055. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6056. }
  6057. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6058. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6059. {
  6060. // Add tag that the object has been initialized
  6061. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6062. // The constructor doesn't return anything,
  6063. // so we have to manually inform the type of
  6064. // the return value
  6065. e.type = tempObj;
  6066. if (!onHeap)
  6067. e.type.dataType.MakeReference(false);
  6068. // Push the address of the object on the stack again
  6069. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6070. }
  6071. MergeExprBytecodeAndType(ctx, &e);
  6072. }
  6073. else
  6074. {
  6075. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6076. }
  6077. }
  6078. }
  6079. }
  6080. }
  6081. return cost;
  6082. }
  6083. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  6084. {
  6085. // First try a ref cast
  6086. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  6087. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  6088. // construct the object through any of the available constructors
  6089. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6090. {
  6091. asCArray<int> funcs;
  6092. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6093. asCArray<asCExprContext *> args;
  6094. args.PushLast(ctx);
  6095. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6096. // Did we find a matching constructor?
  6097. if( funcs.GetLength() == 1 )
  6098. {
  6099. if( generateCode )
  6100. {
  6101. // If the ASHANDLE receives a variable type parameter, then we need to
  6102. // make sure the expression is treated as a handle and not as a value
  6103. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  6104. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  6105. {
  6106. if( !ctx->type.isExplicitHandle )
  6107. {
  6108. asCDataType toHandle = ctx->type.dataType;
  6109. toHandle.MakeHandle(true);
  6110. toHandle.MakeReference(true);
  6111. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  6112. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  6113. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6114. }
  6115. ctx->type.isExplicitHandle = true;
  6116. }
  6117. // TODO: This should really reuse the code from CompileConstructCall
  6118. // Allocate the new object
  6119. asCExprValue tempObj;
  6120. tempObj.dataType = to;
  6121. tempObj.dataType.MakeReference(false);
  6122. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6123. tempObj.dataType.MakeReference(true);
  6124. tempObj.isTemporary = true;
  6125. tempObj.isVariable = true;
  6126. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6127. // Push the address of the object on the stack
  6128. asCExprContext e(engine);
  6129. if( onHeap )
  6130. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6131. PrepareFunctionCall(funcs[0], &e.bc, args);
  6132. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6133. // If the object is allocated on the stack, then call the constructor as a normal function
  6134. if( onHeap )
  6135. {
  6136. int offset = 0;
  6137. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6138. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6139. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6140. }
  6141. else
  6142. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6143. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6144. // Add tag that the object has been initialized
  6145. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6146. // The constructor doesn't return anything,
  6147. // so we have to manually inform the type of
  6148. // the return value
  6149. e.type = tempObj;
  6150. if( !onHeap )
  6151. e.type.dataType.MakeReference(false);
  6152. // Push the address of the object on the stack again
  6153. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6154. MergeExprBytecodeAndType(ctx, &e);
  6155. }
  6156. else
  6157. {
  6158. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6159. }
  6160. }
  6161. }
  6162. // If the base type is still different, and we are allowed to instance
  6163. // another object then we can try an implicit value cast
  6164. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6165. {
  6166. // Attempt implicit value cast
  6167. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  6168. }
  6169. // If we still haven't converted the base type to the correct type, then there is
  6170. // no need to continue as it is not possible to do the conversion
  6171. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  6172. return asCC_NO_CONV;
  6173. if( to.IsObjectHandle() )
  6174. {
  6175. // There is no extra cost in converting to a handle
  6176. // reference to handle -> handle
  6177. // reference -> handle
  6178. // object -> handle
  6179. // handle -> reference to handle
  6180. // reference -> reference to handle
  6181. // object -> reference to handle
  6182. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
  6183. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
  6184. {
  6185. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6186. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6187. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6188. {
  6189. if (generateCode)
  6190. PrepareTemporaryVariable(node, ctx);
  6191. else
  6192. {
  6193. ctx->type.dataType.MakeReadOnly(false);
  6194. ctx->type.isConstant = false;
  6195. }
  6196. // Add the cost for the copy
  6197. cost += asCC_TO_OBJECT_CONV;
  6198. }
  6199. else if( convType != asIC_IMPLICIT_CONV )
  6200. {
  6201. asASSERT(node);
  6202. asCString str;
  6203. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  6204. Error(str, node);
  6205. }
  6206. }
  6207. if( !ctx->type.dataType.IsObjectHandle() )
  6208. {
  6209. // An object type can be directly converted to a handle of the
  6210. // same type by doing a ref copy to a new variable
  6211. if( ctx->type.dataType.SupportHandles() )
  6212. {
  6213. asCDataType dt = ctx->type.dataType;
  6214. dt.MakeHandle(true);
  6215. dt.MakeReference(false);
  6216. if( generateCode )
  6217. {
  6218. // If the expression is already a local variable, then it is not
  6219. // necessary to do a ref copy, as the ref objects on the stack are
  6220. // really handles, only the handles cannot be modified.
  6221. if( ctx->type.isVariable )
  6222. {
  6223. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  6224. ctx->type.dataType.MakeReadOnly(false);
  6225. ctx->type.dataType.MakeHandle(true);
  6226. ctx->type.dataType.MakeReadOnly(true);
  6227. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  6228. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6229. {
  6230. ctx->bc.Instr(asBC_PopPtr);
  6231. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  6232. ctx->type.dataType.MakeReference(true);
  6233. }
  6234. else if( ctx->type.dataType.IsReference() )
  6235. {
  6236. ctx->bc.Instr(asBC_RDSPtr);
  6237. ctx->type.dataType.MakeReference(false);
  6238. }
  6239. }
  6240. else
  6241. {
  6242. int offset = AllocateVariable(dt, true);
  6243. if( ctx->type.dataType.IsReference() )
  6244. ctx->bc.Instr(asBC_RDSPtr);
  6245. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6246. if (dt.IsFuncdef())
  6247. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  6248. else
  6249. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  6250. ctx->bc.Instr(asBC_PopPtr);
  6251. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6252. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6253. if( to.IsReference() )
  6254. dt.MakeReference(true);
  6255. else
  6256. ctx->bc.Instr(asBC_RDSPtr);
  6257. ctx->type.SetVariable(dt, offset, true);
  6258. }
  6259. }
  6260. else
  6261. ctx->type.dataType = dt;
  6262. // When this conversion is done the expression is no longer an lvalue
  6263. ctx->type.isLValue = false;
  6264. }
  6265. }
  6266. if( ctx->type.dataType.IsObjectHandle() )
  6267. {
  6268. // A handle to non-const can be converted to a
  6269. // handle to const, but not the other way
  6270. if( to.IsHandleToConst() )
  6271. ctx->type.dataType.MakeHandleToConst(true);
  6272. // A const handle can be converted to a non-const
  6273. // handle and vice versa as the handle is just a value
  6274. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6275. }
  6276. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6277. {
  6278. if( generateCode )
  6279. {
  6280. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6281. // If the input type is a handle, then a simple ref copy is enough
  6282. bool isExplicitHandle = ctx->type.isExplicitHandle;
  6283. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  6284. // If the input type is read-only we'll need to temporarily
  6285. // remove this constness, otherwise the assignment will fail
  6286. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6287. ctx->type.dataType.MakeReadOnly(false);
  6288. // If the object already is a temporary variable, then the copy
  6289. // doesn't have to be made as it is already a unique object
  6290. PrepareTemporaryVariable(node, ctx);
  6291. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6292. ctx->type.isExplicitHandle = isExplicitHandle;
  6293. }
  6294. // A non-reference can be converted to a reference,
  6295. // by putting the value in a temporary variable
  6296. ctx->type.dataType.MakeReference(true);
  6297. // Since it is a new temporary variable it doesn't have to be const
  6298. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6299. }
  6300. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  6301. {
  6302. Dereference(ctx, generateCode);
  6303. }
  6304. }
  6305. else // if( !to.IsObjectHandle() )
  6306. {
  6307. if( !to.IsReference() )
  6308. {
  6309. // reference to handle -> object
  6310. // handle -> object
  6311. // reference -> object
  6312. // An implicit handle can be converted to an object by adding a check for null pointer
  6313. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6314. {
  6315. if( generateCode )
  6316. {
  6317. if( ctx->type.dataType.IsReference() )
  6318. {
  6319. // The pointer on the stack refers to the handle
  6320. ctx->bc.Instr(asBC_ChkRefS);
  6321. }
  6322. else
  6323. {
  6324. // The pointer on the stack refers to the object
  6325. ctx->bc.Instr(asBC_CHKREF);
  6326. }
  6327. }
  6328. ctx->type.dataType.MakeHandle(false);
  6329. }
  6330. // A const object can be converted to a non-const object through a copy
  6331. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  6332. allowObjectConstruct )
  6333. {
  6334. // Does the object type allow a copy to be made?
  6335. if( ctx->type.dataType.CanBeCopied() )
  6336. {
  6337. if( generateCode )
  6338. {
  6339. // Make a temporary object with the copy
  6340. PrepareTemporaryVariable(node, ctx);
  6341. }
  6342. // In case the object was already in a temporary variable, then the function
  6343. // didn't really do anything so we need to remove the constness here
  6344. ctx->type.dataType.MakeReadOnly(false);
  6345. // Add the cost for the copy
  6346. cost += asCC_TO_OBJECT_CONV;
  6347. }
  6348. }
  6349. if( ctx->type.dataType.IsReference() )
  6350. {
  6351. // This may look strange, but a value type allocated on the stack is already
  6352. // correct, so nothing should be done other than remove the mark as reference.
  6353. // For types allocated on the heap, it is necessary to dereference the pointer
  6354. // that is currently on the stack
  6355. if( IsVariableOnHeap(ctx->type.stackOffset) )
  6356. Dereference(ctx, generateCode);
  6357. else
  6358. ctx->type.dataType.MakeReference(false);
  6359. }
  6360. // A non-const object can be converted to a const object directly
  6361. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6362. {
  6363. ctx->type.dataType.MakeReadOnly(true);
  6364. }
  6365. }
  6366. else // if( to.IsReference() )
  6367. {
  6368. // reference to handle -> reference
  6369. // handle -> reference
  6370. // object -> reference
  6371. if( ctx->type.dataType.IsReference() )
  6372. {
  6373. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6374. {
  6375. // ASHANDLE objects are really value types, so explicit handle can be removed
  6376. ctx->type.isExplicitHandle = false;
  6377. ctx->type.dataType.MakeHandle(false);
  6378. }
  6379. // A reference to a handle can be converted to a reference to an object
  6380. // by first reading the address, then verifying that it is not null
  6381. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6382. {
  6383. ctx->type.dataType.MakeHandle(false);
  6384. if( generateCode )
  6385. ctx->bc.Instr(asBC_ChkRefS);
  6386. }
  6387. // A reference to a non-const can be converted to a reference to a const
  6388. if( to.IsReadOnly() )
  6389. ctx->type.dataType.MakeReadOnly(true);
  6390. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6391. {
  6392. // A reference to a const can be converted to a reference to a
  6393. // non-const by copying the object to a temporary variable
  6394. ctx->type.dataType.MakeReadOnly(false);
  6395. if( generateCode )
  6396. {
  6397. // If the object already is a temporary variable, then the copy
  6398. // doesn't have to be made as it is already a unique object
  6399. PrepareTemporaryVariable(node, ctx);
  6400. }
  6401. // Add the cost for the copy
  6402. cost += asCC_TO_OBJECT_CONV;
  6403. }
  6404. }
  6405. else // if( !ctx->type.dataType.IsReference() )
  6406. {
  6407. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6408. if( ctx->type.dataType.IsObjectHandle() )
  6409. {
  6410. bool readOnly = false;
  6411. if( ctx->type.dataType.IsHandleToConst() )
  6412. readOnly = true;
  6413. if( generateCode )
  6414. {
  6415. if( ctx->type.isVariable )
  6416. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  6417. else
  6418. ctx->bc.Instr(asBC_CHKREF);
  6419. }
  6420. ctx->type.dataType.MakeHandle(false);
  6421. ctx->type.dataType.MakeReference(true);
  6422. // Make sure a handle to const isn't converted to non-const reference
  6423. if( readOnly )
  6424. ctx->type.dataType.MakeReadOnly(true);
  6425. }
  6426. else
  6427. {
  6428. // A value type allocated on the stack is differentiated
  6429. // by it not being a reference. But it can be handled as
  6430. // reference by pushing the pointer on the stack
  6431. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6432. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6433. !IsVariableOnHeap(ctx->type.stackOffset) )
  6434. {
  6435. // Actually the pointer is already pushed on the stack in
  6436. // CompileVariableAccess, so we don't need to do anything else
  6437. }
  6438. else if( generateCode )
  6439. {
  6440. // A non-reference can be converted to a reference,
  6441. // by putting the value in a temporary variable
  6442. // If the input type is read-only we'll need to temporarily
  6443. // remove this constness, otherwise the assignment will fail
  6444. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6445. ctx->type.dataType.MakeReadOnly(false);
  6446. // If the object already is a temporary variable, then the copy
  6447. // doesn't have to be made as it is already a unique object
  6448. PrepareTemporaryVariable(node, ctx);
  6449. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6450. // Add the cost for the copy
  6451. cost += asCC_TO_OBJECT_CONV;
  6452. }
  6453. // This may look strange as the conversion was to make the expression a reference
  6454. // but a value type allocated on the stack is a reference even without the type
  6455. // being marked as such.
  6456. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6457. }
  6458. if (to.IsReadOnly())
  6459. {
  6460. // This doesn't cost anything
  6461. ctx->type.dataType.MakeReadOnly(true);
  6462. }
  6463. if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
  6464. {
  6465. // A const object can be converted to a non-const object through a copy
  6466. if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
  6467. {
  6468. ctx->type.dataType.MakeReadOnly(false);
  6469. if (generateCode)
  6470. {
  6471. // Make a temporary copy of the object in order to make it non-const
  6472. PrepareTemporaryVariable(node, ctx);
  6473. }
  6474. // Add the cost for the copy
  6475. cost += asCC_TO_OBJECT_CONV;
  6476. }
  6477. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6478. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6479. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6480. {
  6481. if (generateCode)
  6482. PrepareTemporaryVariable(node, ctx);
  6483. else
  6484. {
  6485. ctx->type.dataType.MakeReadOnly(false);
  6486. ctx->type.isConstant = false;
  6487. }
  6488. // Add the cost for the copy
  6489. cost += asCC_TO_OBJECT_CONV;
  6490. }
  6491. }
  6492. }
  6493. }
  6494. }
  6495. return cost;
  6496. }
  6497. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct)
  6498. {
  6499. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6500. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6501. if( !objType )
  6502. return asCC_NO_CONV;
  6503. asCArray<int> funcs;
  6504. if (objType->flags & asOBJ_VALUE)
  6505. {
  6506. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6507. for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++)
  6508. {
  6509. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6510. if (func->parameterTypes.GetLength() == 1 &&
  6511. func->parameterTypes[0].IsPrimitive() &&
  6512. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6513. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) )
  6514. {
  6515. funcs.PushLast(func->id);
  6516. }
  6517. }
  6518. }
  6519. else if (objType->flags & asOBJ_REF)
  6520. {
  6521. // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference
  6522. for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++)
  6523. {
  6524. asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]];
  6525. if (func->parameterTypes.GetLength() == 1 &&
  6526. func->parameterTypes[0].IsPrimitive() &&
  6527. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6528. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()))
  6529. {
  6530. funcs.PushLast(func->id);
  6531. }
  6532. }
  6533. }
  6534. if( funcs.GetLength() == 0 )
  6535. return asCC_NO_CONV;
  6536. // Check if it is possible to choose a best match
  6537. asCExprContext arg(engine);
  6538. arg.type = ctx->type;
  6539. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6540. asCArray<asCExprContext*> args;
  6541. args.PushLast(&arg);
  6542. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6543. if( funcs.GetLength() != 1 )
  6544. return asCC_NO_CONV;
  6545. if( !generateCode )
  6546. {
  6547. ctx->type.Set(to);
  6548. return cost;
  6549. }
  6550. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6551. // Clear the type of ctx, as the type is moved to the arg
  6552. ctx->type.SetDummy();
  6553. // Value types and script types are allocated through the constructor
  6554. asCExprValue tempObj;
  6555. bool onHeap = false;
  6556. if (!(objType->flags & asOBJ_REF))
  6557. {
  6558. tempObj.dataType = to;
  6559. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6560. tempObj.dataType.MakeReference(true);
  6561. tempObj.isTemporary = true;
  6562. tempObj.isVariable = true;
  6563. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6564. // Push the address of the object on the stack
  6565. if (onHeap)
  6566. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6567. }
  6568. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6569. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6570. if( !(objType->flags & asOBJ_REF) )
  6571. {
  6572. // If the object is allocated on the stack, then call the constructor as a normal function
  6573. if( onHeap )
  6574. {
  6575. int offset = 0;
  6576. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6577. for( asUINT n = 0; n < args.GetLength(); n++ )
  6578. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6579. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6580. }
  6581. else
  6582. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6583. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6584. // Add tag that the object has been initialized
  6585. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6586. // The constructor doesn't return anything,
  6587. // so we have to manually inform the type of
  6588. // the return value
  6589. ctx->type = tempObj;
  6590. if( !onHeap )
  6591. ctx->type.dataType.MakeReference(false);
  6592. // Push the address of the object on the stack again
  6593. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6594. }
  6595. else
  6596. {
  6597. // Call the factory to create the reference type
  6598. PerformFunctionCall(funcs[0], ctx, false, &args);
  6599. // Make another pass to make sure the result has the correct handle and reference settings
  6600. ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct);
  6601. }
  6602. return cost;
  6603. }
  6604. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6605. {
  6606. asASSERT(from->type.isConstant);
  6607. // TODO: node should be the node of the value that is
  6608. // converted (not the operator that provokes the implicit
  6609. // conversion)
  6610. // If the base type is correct there is no more to do
  6611. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6612. // References cannot be constants
  6613. if( from->type.dataType.IsReference() ) return;
  6614. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6615. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6616. {
  6617. if( from->type.dataType.IsFloatType() ||
  6618. from->type.dataType.IsDoubleType() ||
  6619. from->type.dataType.IsUnsignedType() ||
  6620. from->type.dataType.IsIntegerType() )
  6621. {
  6622. asCDataType targetDt;
  6623. if (to.IsEnumType())
  6624. targetDt = to;
  6625. else
  6626. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6627. // Transform the value
  6628. // Float constants can be implicitly converted to int
  6629. if( from->type.dataType.IsFloatType() )
  6630. {
  6631. float fc = from->type.GetConstantF();
  6632. int ic = int(fc);
  6633. if( float(ic) != fc )
  6634. {
  6635. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6636. }
  6637. from->type.SetConstantDW(targetDt, ic);
  6638. }
  6639. // Double constants can be implicitly converted to int
  6640. else if( from->type.dataType.IsDoubleType() )
  6641. {
  6642. double fc = from->type.GetConstantD();
  6643. int ic = int(fc);
  6644. if( double(ic) != fc )
  6645. {
  6646. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6647. }
  6648. from->type.SetConstantDW(targetDt, ic);
  6649. }
  6650. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6651. {
  6652. // Verify that it is possible to convert to signed without getting negative
  6653. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6654. int(from->type.GetConstantDW()) < 0 &&
  6655. convType != asIC_EXPLICIT_VAL_CAST &&
  6656. node != 0 )
  6657. Warning(TXT_CHANGE_SIGN, node);
  6658. // Convert to 32bit
  6659. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6660. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6661. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6662. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6663. else
  6664. from->type.dataType = targetDt;
  6665. }
  6666. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6667. {
  6668. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6669. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6670. // Convert to 32bit
  6671. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6672. }
  6673. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6674. {
  6675. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6676. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6677. // Convert to 32bit
  6678. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6679. }
  6680. else if (from->type.dataType.IsIntegerType() &&
  6681. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6682. {
  6683. // Convert to 32bit
  6684. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6685. from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
  6686. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6687. from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
  6688. }
  6689. else
  6690. {
  6691. // Only int32 and enums should come here and as these are 32bit
  6692. // already nothing needs to be done except set the target type
  6693. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6694. from->type.dataType.IsEnumType()) &&
  6695. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6696. from->type.dataType = targetDt;
  6697. }
  6698. }
  6699. // Check if a downsize is necessary
  6700. if( to.IsIntegerType() &&
  6701. from->type.dataType.IsIntegerType() &&
  6702. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6703. {
  6704. // Verify if it is possible
  6705. if( to.GetSizeInMemoryBytes() == 1 )
  6706. {
  6707. if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6708. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6709. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
  6710. }
  6711. else if( to.GetSizeInMemoryBytes() == 2 )
  6712. {
  6713. if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6714. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6715. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
  6716. }
  6717. }
  6718. }
  6719. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6720. {
  6721. // Float constants can be implicitly converted to int
  6722. if( from->type.dataType.IsFloatType() )
  6723. {
  6724. float fc = from->type.GetConstantF();
  6725. asINT64 ic = asINT64(fc);
  6726. if( float(ic) != fc )
  6727. {
  6728. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6729. }
  6730. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6731. }
  6732. // Double constants can be implicitly converted to int
  6733. else if( from->type.dataType.IsDoubleType() )
  6734. {
  6735. double fc = from->type.GetConstantD();
  6736. asINT64 ic = asINT64(fc);
  6737. if( double(ic) != fc )
  6738. {
  6739. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6740. }
  6741. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6742. }
  6743. else if( from->type.dataType.IsUnsignedType() )
  6744. {
  6745. // Convert to 64bit
  6746. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6747. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6748. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6749. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6750. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6751. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6752. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6753. {
  6754. if( asINT64(from->type.GetConstantQW()) < 0 )
  6755. {
  6756. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6757. }
  6758. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6759. }
  6760. }
  6761. else if( from->type.dataType.IsIntegerType() )
  6762. {
  6763. // Convert to 64bit
  6764. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6765. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
  6766. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6767. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
  6768. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6769. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6770. }
  6771. }
  6772. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6773. {
  6774. if( from->type.dataType.IsFloatType() )
  6775. {
  6776. float fc = from->type.GetConstantF();
  6777. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6778. // To maintain a consistent behaviour across compilers we convert to int first.
  6779. asUINT uic = asUINT(int(fc));
  6780. if( float(uic) != fc )
  6781. {
  6782. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6783. }
  6784. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6785. // Try once more, in case of a smaller type
  6786. ImplicitConversionConstant(from, to, node, convType);
  6787. }
  6788. else if( from->type.dataType.IsDoubleType() )
  6789. {
  6790. double fc = from->type.GetConstantD();
  6791. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6792. // To maintain a consistent behaviour across compilers we convert to int first.
  6793. asUINT uic = asUINT(int(fc));
  6794. if( double(uic) != fc )
  6795. {
  6796. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6797. }
  6798. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6799. // Try once more, in case of a smaller type
  6800. ImplicitConversionConstant(from, to, node, convType);
  6801. }
  6802. else if( from->type.dataType.IsIntegerType() )
  6803. {
  6804. // Verify that it is possible to convert to unsigned without loosing negative
  6805. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6806. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6807. (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
  6808. (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
  6809. {
  6810. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6811. }
  6812. // Check if any data is lost
  6813. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6814. {
  6815. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6816. }
  6817. // Convert to 32bit
  6818. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6819. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
  6820. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6821. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
  6822. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6823. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6824. else
  6825. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6826. // Try once more, in case of a smaller type
  6827. ImplicitConversionConstant(from, to, node, convType);
  6828. }
  6829. else if( from->type.dataType.IsUnsignedType() &&
  6830. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6831. {
  6832. // Convert to 32bit
  6833. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6834. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6835. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6836. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6837. // Try once more, in case of a smaller type
  6838. ImplicitConversionConstant(from, to, node, convType);
  6839. }
  6840. else if( from->type.dataType.IsUnsignedType() &&
  6841. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6842. {
  6843. // Verify if it is possible
  6844. if( to.GetSizeInMemoryBytes() == 1 )
  6845. {
  6846. if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() )
  6847. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6848. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6849. }
  6850. else if( to.GetSizeInMemoryBytes() == 2 )
  6851. {
  6852. if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW())
  6853. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6854. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6855. }
  6856. else if (to.GetSizeInMemoryBytes() == 4)
  6857. {
  6858. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6859. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6860. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6861. }
  6862. }
  6863. }
  6864. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6865. {
  6866. if( from->type.dataType.IsFloatType() )
  6867. {
  6868. float fc = from->type.GetConstantF();
  6869. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6870. asQWORD uic = asQWORD(asINT64(fc));
  6871. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6872. // MSVC6 doesn't support this conversion
  6873. if( float(uic) != fc )
  6874. {
  6875. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6876. }
  6877. #endif
  6878. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6879. }
  6880. else if( from->type.dataType.IsDoubleType() )
  6881. {
  6882. double fc = from->type.GetConstantD();
  6883. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6884. asQWORD uic = asQWORD(asINT64(fc));
  6885. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6886. // MSVC6 doesn't support this conversion
  6887. if( double(uic) != fc )
  6888. {
  6889. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6890. }
  6891. #endif
  6892. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6893. }
  6894. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6895. {
  6896. // Convert to 64bit
  6897. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6898. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
  6899. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6900. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
  6901. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6902. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  6903. // Verify that it is possible to convert to unsigned without loosing negative
  6904. if( asINT64(from->type.GetConstantQW()) < 0 )
  6905. {
  6906. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6907. }
  6908. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6909. }
  6910. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6911. {
  6912. // Verify that it is possible to convert to unsigned without loosing negative
  6913. if( asINT64(from->type.GetConstantQW()) < 0 )
  6914. {
  6915. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6916. }
  6917. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6918. }
  6919. else if( from->type.dataType.IsUnsignedType() )
  6920. {
  6921. // Convert to 64bit
  6922. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6923. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  6924. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6925. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  6926. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6927. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  6928. }
  6929. }
  6930. else if( to.IsFloatType() )
  6931. {
  6932. if( from->type.dataType.IsDoubleType() )
  6933. {
  6934. double ic = from->type.GetConstantD();
  6935. float fc = float(ic);
  6936. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6937. }
  6938. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6939. {
  6940. // Must properly convert value in case the from value is smaller
  6941. int ic;
  6942. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6943. ic = (asINT8)from->type.GetConstantB();
  6944. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6945. ic = (asINT16)from->type.GetConstantW();
  6946. else
  6947. ic = (int)from->type.GetConstantDW();
  6948. float fc = float(ic);
  6949. if( int(fc) != ic )
  6950. {
  6951. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6952. }
  6953. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6954. }
  6955. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6956. {
  6957. float fc = float(asINT64(from->type.GetConstantQW()));
  6958. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  6959. {
  6960. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6961. }
  6962. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6963. }
  6964. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6965. {
  6966. // Must properly convert value in case the from value is smaller
  6967. unsigned int uic;
  6968. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6969. uic = from->type.GetConstantB();
  6970. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6971. uic = from->type.GetConstantW();
  6972. else
  6973. uic = from->type.GetConstantDW();
  6974. float fc = float(uic);
  6975. if( (unsigned int)(fc) != uic )
  6976. {
  6977. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6978. }
  6979. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6980. }
  6981. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6982. {
  6983. float fc = float((asINT64)from->type.GetConstantQW());
  6984. if( asQWORD(fc) != from->type.GetConstantQW())
  6985. {
  6986. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6987. }
  6988. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6989. }
  6990. }
  6991. else if( to.IsDoubleType() )
  6992. {
  6993. if( from->type.dataType.IsFloatType() )
  6994. {
  6995. float ic = from->type.GetConstantF();
  6996. double fc = double(ic);
  6997. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6998. }
  6999. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7000. {
  7001. // Must properly convert value in case the from value is smaller
  7002. int ic;
  7003. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7004. ic = (asINT8)from->type.GetConstantB();
  7005. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7006. ic = (asINT16)from->type.GetConstantW();
  7007. else
  7008. ic = (int)from->type.GetConstantDW();
  7009. double fc = double(ic);
  7010. if( int(fc) != ic )
  7011. {
  7012. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7013. }
  7014. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7015. }
  7016. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7017. {
  7018. double fc = double(asINT64(from->type.GetConstantQW()));
  7019. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7020. {
  7021. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7022. }
  7023. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7024. }
  7025. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7026. {
  7027. // Must properly convert value in case the from value is smaller
  7028. unsigned int uic;
  7029. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7030. uic = from->type.GetConstantB();
  7031. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7032. uic = from->type.GetConstantW();
  7033. else
  7034. uic = from->type.GetConstantDW();
  7035. double fc = double(uic);
  7036. if( (unsigned int)(fc) != uic )
  7037. {
  7038. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7039. }
  7040. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7041. }
  7042. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7043. {
  7044. double fc = double((asINT64)from->type.GetConstantQW());
  7045. if( asQWORD(fc) != from->type.GetConstantQW())
  7046. {
  7047. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7048. }
  7049. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7050. }
  7051. }
  7052. }
  7053. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  7054. {
  7055. // Don't allow any operators on expressions that take address of class method
  7056. // If methodName is set but the type is not an object, then it is a global function
  7057. if( lctx->methodName != "" || rctx->IsClassMethod() )
  7058. {
  7059. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  7060. return -1;
  7061. }
  7062. // Implicit handle types should always be treated as handles in assignments
  7063. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  7064. {
  7065. lctx->type.dataType.MakeHandle(true);
  7066. lctx->type.isExplicitHandle = true;
  7067. }
  7068. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  7069. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  7070. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  7071. (!lctx->type.dataType.GetBehaviour() || !lctx->type.dataType.GetBehaviour()->copy))
  7072. lctx->type.isExplicitHandle = true;
  7073. // If the left hand expression is a property accessor, then that should be used
  7074. // to do the assignment instead of the ordinary operator. The exception is when
  7075. // the property accessor is for a handle property, and the operation is a value
  7076. // assignment.
  7077. if( (lctx->property_get || lctx->property_set) &&
  7078. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  7079. {
  7080. if( op != ttAssignment )
  7081. {
  7082. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  7083. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  7084. }
  7085. // It is not allowed to do a handle assignment on a property
  7086. // accessor that doesn't take a handle in the set accessor.
  7087. if( lctx->property_set && lctx->type.isExplicitHandle )
  7088. {
  7089. // set_opIndex has 2 arguments, where as normal setters have only 1
  7090. asCArray<asCDataType>& parameterTypes =
  7091. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  7092. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  7093. {
  7094. // Process the property to free the memory
  7095. ProcessPropertySetAccessor(lctx, rctx, opNode);
  7096. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  7097. return -1;
  7098. }
  7099. }
  7100. MergeExprBytecodeAndType(ctx, lctx);
  7101. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  7102. }
  7103. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7104. {
  7105. // Get the handle to the object that will be used for the value assignment
  7106. ProcessPropertyGetAccessor(lctx, opNode);
  7107. }
  7108. if( lctx->type.dataType.IsPrimitive() )
  7109. {
  7110. if( !lctx->type.isLValue )
  7111. {
  7112. Error(TXT_NOT_LVALUE, lexpr);
  7113. return -1;
  7114. }
  7115. if( op != ttAssignment )
  7116. {
  7117. // Compute the operator before the assignment
  7118. asCExprValue lvalue = lctx->type;
  7119. if( lctx->type.isTemporary && !lctx->type.isVariable )
  7120. {
  7121. // The temporary variable must not be freed until the
  7122. // assignment has been performed. lvalue still holds
  7123. // the information about the temporary variable
  7124. lctx->type.isTemporary = false;
  7125. }
  7126. asCExprContext o(engine);
  7127. CompileOperator(opNode, lctx, rctx, &o);
  7128. MergeExprBytecode(rctx, &o);
  7129. rctx->type = o.type;
  7130. // Convert the rvalue to the right type and validate it
  7131. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  7132. MergeExprBytecode(ctx, rctx);
  7133. lctx->type = lvalue;
  7134. // The lvalue continues the same, either it was a variable, or a reference in the register
  7135. }
  7136. else
  7137. {
  7138. // Convert the rvalue to the right type and validate it
  7139. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  7140. MergeExprBytecode(ctx, rctx);
  7141. MergeExprBytecode(ctx, lctx);
  7142. }
  7143. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7144. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7145. ctx->type = lctx->type;
  7146. }
  7147. else if( lctx->type.isExplicitHandle )
  7148. {
  7149. if( !lctx->type.isLValue )
  7150. {
  7151. Error(TXT_NOT_LVALUE, lexpr);
  7152. return -1;
  7153. }
  7154. // Object handles don't have any compound assignment operators
  7155. if( op != ttAssignment )
  7156. {
  7157. asCString str;
  7158. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7159. Error(str, lexpr);
  7160. return -1;
  7161. }
  7162. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  7163. {
  7164. // The object is a value type but that should be treated as a handle
  7165. // Make sure the right hand value is a handle
  7166. if( !rctx->type.isExplicitHandle &&
  7167. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  7168. {
  7169. // Function names can be considered handles already
  7170. if( rctx->methodName == "" )
  7171. {
  7172. asCDataType dt = rctx->type.dataType;
  7173. dt.MakeHandle(true);
  7174. dt.MakeReference(false);
  7175. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  7176. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7177. {
  7178. asCString str;
  7179. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7180. Error(str, rexpr);
  7181. return -1;
  7182. }
  7183. }
  7184. if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles())
  7185. {
  7186. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr);
  7187. return -1;
  7188. }
  7189. // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
  7190. // the code for moving the argument to the stack may not know to correctly handle the argument type
  7191. // in case of variable parameter type.
  7192. rctx->type.isExplicitHandle = true;
  7193. }
  7194. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  7195. {
  7196. // An overloaded assignment operator was found (or a compilation error occured)
  7197. return 0;
  7198. }
  7199. // The object must implement the opAssign method
  7200. asCString msg;
  7201. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7202. Error(msg.AddressOf(), opNode);
  7203. return -1;
  7204. }
  7205. else
  7206. {
  7207. asCDataType dt = lctx->type.dataType;
  7208. dt.MakeReference(false);
  7209. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
  7210. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7211. {
  7212. asCString str;
  7213. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7214. Error(str, rexpr);
  7215. return -1;
  7216. }
  7217. MergeExprBytecode(ctx, rctx);
  7218. MergeExprBytecode(ctx, lctx);
  7219. if(!rctx->type.isRefSafe)
  7220. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7221. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7222. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7223. ctx->type = lctx->type;
  7224. // After the handle assignment the original handle is left on the stack
  7225. ctx->type.dataType.MakeReference(false);
  7226. }
  7227. }
  7228. else // if( lctx->type.dataType.IsObject() )
  7229. {
  7230. // The lvalue reference may be marked as a temporary, if for example
  7231. // it was originated as a handle returned from a function. In such
  7232. // cases it must be possible to assign values to it anyway.
  7233. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7234. {
  7235. // Convert the handle to a object reference
  7236. asCDataType to;
  7237. to = lctx->type.dataType;
  7238. to.MakeHandle(false);
  7239. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  7240. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  7241. }
  7242. // Check for overloaded assignment operator
  7243. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  7244. {
  7245. // An overloaded assignment operator was found (or a compilation error occured)
  7246. return 0;
  7247. }
  7248. // No registered operator was found. In case the operation is a direct
  7249. // assignment and the rvalue is the same type as the lvalue, then we can
  7250. // still use the byte-for-byte copy to do the assignment
  7251. if( op != ttAssignment )
  7252. {
  7253. asCString str;
  7254. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7255. Error(str, lexpr);
  7256. return -1;
  7257. }
  7258. // If the left hand expression is simple, i.e. without any
  7259. // function calls or allocations of memory, then we can avoid
  7260. // doing a copy of the right hand expression (done by PrepareArgument).
  7261. // Instead the reference to the value can be placed directly on the
  7262. // stack.
  7263. //
  7264. // This optimization should only be done for value types, where
  7265. // the application developer is responsible for making the
  7266. // implementation safe against unwanted destruction of the input
  7267. // reference before the time.
  7268. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  7269. // Implicitly convert the rvalue to the type of the lvalue
  7270. bool needConversion = false;
  7271. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7272. needConversion = true;
  7273. if( !simpleExpr || needConversion )
  7274. {
  7275. asCDataType dt = lctx->type.dataType;
  7276. dt.MakeReference(true);
  7277. // A funcdef can be accessed by ref, but only as read-only
  7278. if( dt.IsFuncdef() && !dt.IsObjectHandle() )
  7279. dt.MakeReadOnly(true);
  7280. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  7281. if( r < 0 )
  7282. return -1;
  7283. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7284. {
  7285. asCString str;
  7286. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7287. Error(str, rexpr);
  7288. return -1;
  7289. }
  7290. }
  7291. else
  7292. {
  7293. // Process any property accessor first, before placing the final reference on the stack
  7294. ProcessPropertyGetAccessor(rctx, rexpr);
  7295. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  7296. rctx->bc.Instr(asBC_RDSPtr);
  7297. }
  7298. MergeExprBytecode(ctx, rctx);
  7299. MergeExprBytecode(ctx, lctx);
  7300. if( !simpleExpr || needConversion )
  7301. {
  7302. if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) )
  7303. {
  7304. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  7305. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  7306. // as the value allocated on the stack is guaranteed to be safe.
  7307. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  7308. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  7309. else
  7310. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7311. }
  7312. }
  7313. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7314. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7315. ctx->type = lctx->type;
  7316. }
  7317. return 0;
  7318. }
  7319. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  7320. {
  7321. asASSERT(expr->nodeType == snAssignment);
  7322. asCScriptNode *lexpr = expr->firstChild;
  7323. if( lexpr->next )
  7324. {
  7325. // Compile the two expression terms
  7326. asCExprContext lctx(engine), rctx(engine);
  7327. int rr = CompileAssignment(lexpr->next->next, &rctx);
  7328. int lr = CompileCondition(lexpr, &lctx);
  7329. if( lr >= 0 && rr >= 0 )
  7330. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  7331. // Since the operands failed, the assignment was not computed
  7332. ctx->type.SetDummy();
  7333. return -1;
  7334. }
  7335. return CompileCondition(lexpr, ctx);
  7336. }
  7337. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  7338. {
  7339. asCExprValue ctype;
  7340. // Compile the conditional expression
  7341. asCScriptNode *cexpr = expr->firstChild;
  7342. if( cexpr->next )
  7343. {
  7344. //-------------------------------
  7345. // Compile the condition
  7346. asCExprContext e(engine);
  7347. int r = CompileExpression(cexpr, &e);
  7348. if( r < 0 )
  7349. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7350. // Allow value types to be converted to bool using 'bool opImplConv()'
  7351. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  7352. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  7353. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7354. {
  7355. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  7356. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7357. }
  7358. ctype = e.type;
  7359. ProcessPropertyGetAccessor(&e, cexpr);
  7360. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  7361. ProcessDeferredParams(&e);
  7362. //-------------------------------
  7363. // Compile the left expression
  7364. asCExprContext le(engine);
  7365. int lr = CompileAssignment(cexpr->next, &le);
  7366. // Resolve any function names already
  7367. DetermineSingleFunc(&le, cexpr->next);
  7368. //-------------------------------
  7369. // Compile the right expression
  7370. asCExprContext re(engine);
  7371. int rr = CompileAssignment(cexpr->next->next, &re);
  7372. DetermineSingleFunc(&re, cexpr->next->next);
  7373. if( lr >= 0 && rr >= 0 )
  7374. {
  7375. // Don't allow any operators on expressions that take address of class method
  7376. if( le.IsClassMethod() || re.IsClassMethod() )
  7377. {
  7378. Error(TXT_INVALID_OP_ON_METHOD, expr);
  7379. return -1;
  7380. }
  7381. ProcessPropertyGetAccessor(&le, cexpr->next);
  7382. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  7383. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  7384. // Allow a 0 or null in the first case to be implicitly converted to the second type
  7385. if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() )
  7386. {
  7387. asCDataType to = re.type.dataType;
  7388. to.MakeReference(false);
  7389. to.MakeReadOnly(true);
  7390. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7391. }
  7392. else if( le.type.IsNullConstant() )
  7393. {
  7394. asCDataType to = re.type.dataType;
  7395. to.MakeHandle(true);
  7396. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7397. }
  7398. // Allow either case to be converted to const @ if the other is const @
  7399. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  7400. {
  7401. le.type.dataType.MakeHandleToConst(true);
  7402. re.type.dataType.MakeHandleToConst(true);
  7403. }
  7404. // Allow an anonymous initialization list to be converted to the type in the other condition
  7405. if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
  7406. {
  7407. asCDataType to = re.type.dataType;
  7408. to.MakeReference(false);
  7409. to.MakeReadOnly(false);
  7410. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7411. }
  7412. else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory)
  7413. {
  7414. asCDataType to = le.type.dataType;
  7415. to.MakeReference(false);
  7416. to.MakeReadOnly(false);
  7417. ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7418. }
  7419. if (le.IsAnonymousInitList() )
  7420. {
  7421. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
  7422. return -1;
  7423. }
  7424. else if (re.IsAnonymousInitList())
  7425. {
  7426. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next);
  7427. return -1;
  7428. }
  7429. //---------------------------------
  7430. // Output the byte code
  7431. int afterLabel = nextLabel++;
  7432. int elseLabel = nextLabel++;
  7433. // If left expression is void, then we don't need to store the result
  7434. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  7435. {
  7436. // Put the code for the condition expression on the output
  7437. MergeExprBytecode(ctx, &e);
  7438. // Added the branch decision
  7439. ctx->type = e.type;
  7440. ConvertToVariable(ctx);
  7441. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7442. ctx->bc.Instr(asBC_ClrHi);
  7443. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7444. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7445. // Add the left expression
  7446. MergeExprBytecode(ctx, &le);
  7447. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7448. // Add the right expression
  7449. ctx->bc.Label((short)elseLabel);
  7450. MergeExprBytecode(ctx, &re);
  7451. ctx->bc.Label((short)afterLabel);
  7452. // Make sure both expressions have the same type
  7453. if( le.type.dataType != re.type.dataType )
  7454. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7455. // Set the type of the result
  7456. ctx->type = le.type;
  7457. }
  7458. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7459. {
  7460. // Special case for when both results are 'null'
  7461. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7462. // Put the code for the condition expression on the output
  7463. MergeExprBytecode(ctx, &e);
  7464. // Load the result into the register, but ignore the value since both paths give the same response
  7465. ctx->type = e.type;
  7466. ConvertToVariable(ctx);
  7467. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7468. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7469. // Return a null constant
  7470. ctx->bc.Instr(asBC_PshNull);
  7471. ctx->type.SetNullConstant();
  7472. }
  7473. else
  7474. {
  7475. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7476. //
  7477. // Restrictions for the condition to be used as lvalue:
  7478. // 1. both b and c must be of the same type and be lvalue references
  7479. // 2. neither of the expressions can have any deferred arguments
  7480. // that would have to be cleaned up after the reference
  7481. // 3. neither expression can be temporary
  7482. //
  7483. // If either expression is local, the resulting lvalue is not valid
  7484. // for return since it is not allowed to return references to local
  7485. // variables.
  7486. //
  7487. // The reference to the local variable must be loaded into the register,
  7488. // the resulting expression must not be considered as a local variable
  7489. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7490. if( le.type.isLValue && re.type.isLValue &&
  7491. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 &&
  7492. !le.type.isTemporary && !re.type.isTemporary &&
  7493. le.type.dataType == re.type.dataType )
  7494. {
  7495. // Put the code for the condition expression on the output
  7496. MergeExprBytecode(ctx, &e);
  7497. // Add the branch decision
  7498. ctx->type = e.type;
  7499. ConvertToVariable(ctx);
  7500. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7501. ctx->bc.Instr(asBC_ClrHi);
  7502. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7503. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7504. // Start of the left expression
  7505. MergeExprBytecode(ctx, &le);
  7506. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7507. {
  7508. // Load the address of the variable into the register
  7509. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  7510. }
  7511. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7512. // Start of the right expression
  7513. ctx->bc.Label((short)elseLabel);
  7514. MergeExprBytecode(ctx, &re);
  7515. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7516. {
  7517. // Load the address of the variable into the register
  7518. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  7519. }
  7520. ctx->bc.Label((short)afterLabel);
  7521. // In case the options were to objects, it is necessary to dereference the pointer on
  7522. // the stack so it will point to the actual object, instead of the variable
  7523. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7524. {
  7525. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7526. ctx->bc.Instr(asBC_RDSPtr);
  7527. }
  7528. // The result is an lvalue
  7529. ctx->type.isLValue = true;
  7530. ctx->type.dataType = le.type.dataType;
  7531. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7532. ctx->type.dataType.MakeReference(true);
  7533. else
  7534. ctx->type.dataType.MakeReference(false);
  7535. // It can't be a treated as a variable, since we don't know which one was used
  7536. ctx->type.isVariable = false;
  7537. ctx->type.isTemporary = false;
  7538. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7539. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7540. }
  7541. else
  7542. {
  7543. // Allocate temporary variable and copy the result to that one
  7544. asCExprValue temp;
  7545. temp = le.type;
  7546. temp.dataType.MakeReference(false);
  7547. temp.dataType.MakeReadOnly(false);
  7548. // Make sure the variable isn't used in any of the expressions,
  7549. // as it would be overwritten which may cause crashes or less visible bugs
  7550. int l = int(reservedVariables.GetLength());
  7551. e.bc.GetVarsUsed(reservedVariables);
  7552. le.bc.GetVarsUsed(reservedVariables);
  7553. re.bc.GetVarsUsed(reservedVariables);
  7554. int offset = AllocateVariable(temp.dataType, true, false);
  7555. reservedVariables.SetLength(l);
  7556. temp.SetVariable(temp.dataType, offset, true);
  7557. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7558. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7559. // Put the code for the condition expression on the output
  7560. MergeExprBytecode(ctx, &e);
  7561. // Add the branch decision
  7562. ctx->type = e.type;
  7563. ConvertToVariable(ctx);
  7564. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7565. ctx->bc.Instr(asBC_ClrHi);
  7566. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7567. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7568. // Assign the result of the left expression to the temporary variable
  7569. asCExprValue rtemp;
  7570. rtemp = temp;
  7571. if( rtemp.dataType.IsObjectHandle() )
  7572. rtemp.isExplicitHandle = true;
  7573. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7574. MergeExprBytecode(ctx, &le);
  7575. if( !rtemp.dataType.IsPrimitive() )
  7576. {
  7577. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7578. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7579. }
  7580. asCExprValue result;
  7581. result = rtemp;
  7582. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7583. if( !result.dataType.IsPrimitive() )
  7584. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7585. // Release the old temporary variable
  7586. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7587. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7588. // Start of the right expression
  7589. ctx->bc.Label((short)elseLabel);
  7590. // Copy the result to the same temporary variable
  7591. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7592. MergeExprBytecode(ctx, &re);
  7593. if( !rtemp.dataType.IsPrimitive() )
  7594. {
  7595. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7596. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7597. }
  7598. result = rtemp;
  7599. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7600. if( !result.dataType.IsPrimitive() )
  7601. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7602. // Release the old temporary variable
  7603. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7604. ctx->bc.Label((short)afterLabel);
  7605. // Make sure both expressions have the same type
  7606. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  7607. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7608. // Set the temporary variable as output
  7609. ctx->type = rtemp;
  7610. ctx->type.isExplicitHandle = isExplicitHandle;
  7611. if( !ctx->type.dataType.IsPrimitive() )
  7612. {
  7613. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7614. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7615. }
  7616. // Make sure the output isn't marked as being a literal constant
  7617. ctx->type.isConstant = false;
  7618. }
  7619. }
  7620. }
  7621. else
  7622. {
  7623. ctx->type.SetDummy();
  7624. return -1;
  7625. }
  7626. }
  7627. else
  7628. return CompileExpression(cexpr, ctx);
  7629. return 0;
  7630. }
  7631. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7632. {
  7633. asASSERT(expr->nodeType == snExpression);
  7634. // Convert to polish post fix, i.e: a+b => ab+
  7635. asCArray<asCScriptNode *> postfix;
  7636. ConvertToPostFix(expr, postfix);
  7637. // Compile the postfix formatted expression
  7638. return CompilePostFixExpression(&postfix, ctx);
  7639. }
  7640. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7641. {
  7642. // The algorithm that I've implemented here is similar to
  7643. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7644. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7645. // Count the nodes in order to preallocate the buffers
  7646. int count = 0;
  7647. asCScriptNode *node = expr->firstChild;
  7648. while( node )
  7649. {
  7650. count++;
  7651. node = node->next;
  7652. }
  7653. asCArray<asCScriptNode *> stackA(count);
  7654. asCArray<asCScriptNode *> &stackB = postfix;
  7655. stackB.Allocate(count, false);
  7656. node = expr->firstChild;
  7657. while( node )
  7658. {
  7659. int precedence = GetPrecedence(node);
  7660. while( stackA.GetLength() > 0 &&
  7661. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7662. stackB.PushLast(stackA.PopLast());
  7663. stackA.PushLast(node);
  7664. node = node->next;
  7665. }
  7666. while( stackA.GetLength() > 0 )
  7667. stackB.PushLast(stackA.PopLast());
  7668. }
  7669. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7670. {
  7671. // Shouldn't send any byte code
  7672. asASSERT(ctx->bc.GetLastInstr() == -1);
  7673. // Set the context to a dummy type to avoid further
  7674. // errors in case the expression fails to compile
  7675. ctx->type.SetDummy();
  7676. // Evaluate the operands and operators
  7677. asCArray<asCExprContext*> free;
  7678. asCArray<asCExprContext*> expr;
  7679. int ret = 0;
  7680. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7681. {
  7682. asCScriptNode *node = (*postfix)[n];
  7683. if( node->nodeType == snExprTerm )
  7684. {
  7685. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7686. expr.PushLast(e);
  7687. e->exprNode = node;
  7688. ret = CompileExpressionTerm(node, e);
  7689. }
  7690. else
  7691. {
  7692. asCExprContext *r = expr.PopLast();
  7693. asCExprContext *l = expr.PopLast();
  7694. // Now compile the operator
  7695. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7696. ret = CompileOperator(node, l, r, e);
  7697. expr.PushLast(e);
  7698. // Free the operands
  7699. l->Clear();
  7700. free.PushLast(l);
  7701. r->Clear();
  7702. free.PushLast(r);
  7703. }
  7704. }
  7705. if( ret == 0 )
  7706. {
  7707. asASSERT(expr.GetLength() == 1);
  7708. // The final result should be moved to the output context
  7709. MergeExprBytecodeAndType(ctx, expr[0]);
  7710. }
  7711. // Clean up
  7712. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7713. asDELETE(expr[e], asCExprContext);
  7714. for( asUINT f = 0; f < free.GetLength(); f++ )
  7715. asDELETE(free[f], asCExprContext);
  7716. return ret;
  7717. }
  7718. int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7719. {
  7720. asASSERT(node->nodeType == snInitList);
  7721. // Do not allow constructing non-shared types in shared functions
  7722. if (outFunc->IsShared() &&
  7723. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7724. {
  7725. asCString msg;
  7726. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7727. Error(msg, node);
  7728. }
  7729. // If this is compiled from a default arg, then use the script code for the default arg
  7730. asCScriptCode *origCode = script;
  7731. if (ctx->origCode)
  7732. script = ctx->origCode;
  7733. // Allocate and initialize the temporary object
  7734. int offset = AllocateVariable(dt, true);
  7735. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7736. // Push the reference to the object on the stack
  7737. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7738. ctx->type.SetVariable(dt, offset, true);
  7739. ctx->type.isLValue = false;
  7740. // If the variable is allocated on the heap we have a reference,
  7741. // otherwise the actual object pointer is pushed on the stack.
  7742. if (IsVariableOnHeap(offset))
  7743. ctx->type.dataType.MakeReference(true);
  7744. // Clear the flag for anonymous initalization list as it is no
  7745. // longer true now that the object has been initialized.
  7746. ctx->isAnonymousInitList = false;
  7747. ctx->origCode = 0;
  7748. script = origCode;
  7749. return 0;
  7750. }
  7751. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7752. {
  7753. // Shouldn't send any byte code
  7754. asASSERT(ctx->bc.GetLastInstr() == -1);
  7755. // Check if this is an initialization of a temp object with an initialization list
  7756. if (node->firstChild )
  7757. {
  7758. if (node->firstChild->nodeType == snDataType)
  7759. {
  7760. // Determine the type of the temporary object
  7761. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7762. return CompileAnonymousInitList(node->lastChild, ctx, dt);
  7763. }
  7764. else if (node->firstChild->nodeType == snInitList)
  7765. {
  7766. // As the type is not yet known, the init list will be compiled at a
  7767. // later time when the type can be determined from the destination
  7768. ctx->SetAnonymousInitList(node->firstChild, script);
  7769. return 0;
  7770. }
  7771. }
  7772. // Set the type as a dummy by default, in case of any compiler errors
  7773. ctx->type.SetDummy();
  7774. // Compile the value node
  7775. asCScriptNode *vnode = node->firstChild;
  7776. while( vnode->nodeType != snExprValue )
  7777. vnode = vnode->next;
  7778. asCExprContext v(engine);
  7779. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  7780. // Compile post fix operators
  7781. asCScriptNode *pnode = vnode->next;
  7782. while( pnode )
  7783. {
  7784. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  7785. pnode = pnode->next;
  7786. }
  7787. // Compile pre fix operators
  7788. pnode = vnode->prev;
  7789. while( pnode )
  7790. {
  7791. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  7792. pnode = pnode->prev;
  7793. }
  7794. // Return the byte code and final type description
  7795. MergeExprBytecodeAndType(ctx, &v);
  7796. return 0;
  7797. }
  7798. // returns:
  7799. // SL_LOCALCONST = local constant
  7800. // SL_LOCALVAR = local variable
  7801. // SL_NOMATCH = no match
  7802. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult)
  7803. {
  7804. sVariable *v = 0;
  7805. if (variables)
  7806. v = variables->GetVariable(name.AddressOf());
  7807. if (v)
  7808. {
  7809. if (v->isPureConstant)
  7810. {
  7811. outResult->type.SetConstantData(v->type, v->constantValue);
  7812. return SL_LOCALCONST;
  7813. }
  7814. outResult->type.SetVariable(v->type, v->stackOffset, false);
  7815. return SL_LOCALVAR;
  7816. }
  7817. return SL_NOMATCH;
  7818. }
  7819. // returns:
  7820. // SL_CLASSPROPACCESS = class property accessor
  7821. // SL_CLASSPROP = class property
  7822. // SL_CLASSMETHOD = class method
  7823. // SL_CLASSTYPE = class child type
  7824. // SL_NOMATCH = no match
  7825. // SL_ERROR = error
  7826. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult)
  7827. {
  7828. // See if there are any matching property accessors
  7829. asCExprContext access(engine);
  7830. access.type.Set(asCDataType::CreateType(objType, false));
  7831. access.type.dataType.MakeReference(true);
  7832. int r = 0;
  7833. // Indexed property access
  7834. asCExprContext dummyArg(engine);
  7835. r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true);
  7836. if (r == 0)
  7837. {
  7838. // Normal property access
  7839. r = FindPropertyAccessor(name, &access, 0, 0, true);
  7840. }
  7841. if (r < 0) return SL_ERROR;
  7842. if (access.property_get || access.property_set)
  7843. {
  7844. MergeExprBytecodeAndType(outResult, &access);
  7845. outResult->type.dataType.SetTypeInfo(objType);
  7846. return SL_CLASSPROPACCESS;
  7847. }
  7848. // Look for matching properties
  7849. asCDataType dt;
  7850. dt = asCDataType::CreateType(objType, false);
  7851. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7852. if (prop)
  7853. {
  7854. outResult->type.dataType.SetTypeInfo(objType);
  7855. return SL_CLASSPROP;
  7856. }
  7857. // If it is not a property, it may still be the name of a method
  7858. asCObjectType *ot = objType;
  7859. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  7860. {
  7861. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7862. if (f->name == name &&
  7863. (builder->module->accessMask & f->accessMask))
  7864. {
  7865. outResult->type.dataType.SetTypeInfo(objType);
  7866. return SL_CLASSMETHOD;
  7867. }
  7868. }
  7869. // If it is not a method, then it can still be a child type
  7870. for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
  7871. {
  7872. if (ot->childFuncDefs[n]->name == name)
  7873. {
  7874. outResult->type.dataType.SetTypeInfo(objType);
  7875. return SL_CLASSTYPE;
  7876. }
  7877. }
  7878. return SL_NOMATCH;
  7879. }
  7880. // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy
  7881. // The 'outResult' will be used to return info on what was identified, but no code will be produced by this function
  7882. // input:
  7883. // name = the name of the symbol to look for
  7884. // scope = explicit scope informed
  7885. // 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
  7886. // returns:
  7887. // SL_NOMATCH = no matching symbol
  7888. // SL_LOCALCONST = local constant
  7889. // SL_LOCALVAR = local variable
  7890. // SL_THISPTR = this pointer
  7891. // SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found
  7892. // SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found
  7893. // SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found
  7894. // SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found
  7895. // SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7896. // SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7897. // SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7898. // SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7899. // SL_GLOBALTYPE = type, lookupResult->dataType holds the type
  7900. // SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7901. // SL_ERROR = error
  7902. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult)
  7903. {
  7904. asASSERT(outResult);
  7905. // It is a local variable or parameter?
  7906. // This is not accessible by default arg expressions
  7907. if (!isCompilingDefaultArg && scope == "" && !objType )
  7908. {
  7909. SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult);
  7910. if (r != 0)
  7911. return r;
  7912. }
  7913. // Is it a class member?
  7914. // This is not accessible by default arg expressions
  7915. if (!isCompilingDefaultArg && scope == "" && ((objType) || (outFunc && outFunc->objectType)))
  7916. {
  7917. if (name == THIS_TOKEN && !objType)
  7918. {
  7919. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  7920. // The object pointer is located at stack position 0
  7921. outResult->type.SetVariable(dt, 0, false);
  7922. return SL_THISPTR;
  7923. }
  7924. if (m_isConstructor && name == SUPER_TOKEN && !objType)
  7925. {
  7926. // If the class is derived from another class, then super can be used to call the base' class constructor
  7927. if (outFunc && outFunc->objectType->derivedFrom)
  7928. {
  7929. outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom);
  7930. return SL_CLASSMETHOD;
  7931. }
  7932. }
  7933. // Look for members in the type
  7934. SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult);
  7935. if (r != 0)
  7936. return r;
  7937. }
  7938. // Recursively search parent namespaces for global entities
  7939. asSNameSpace *currNamespace = DetermineNameSpace("");
  7940. while( !objType && currNamespace )
  7941. {
  7942. asCString currScope = scope;
  7943. // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
  7944. // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
  7945. int n = currScope.FindLast("::");
  7946. asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
  7947. asCString nsName = n >= 0 ? currScope.SubString(0, n) : "";
  7948. // If the scope represents a type that the current class inherits
  7949. // from then that should be used instead of going through the namespaces
  7950. if (nsName == "" && (outFunc && outFunc->objectType))
  7951. {
  7952. asCObjectType *ot = outFunc->objectType;
  7953. while (ot)
  7954. {
  7955. if (ot->name == typeName)
  7956. {
  7957. SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult);
  7958. if (r != 0)
  7959. return r;
  7960. }
  7961. ot = ot->derivedFrom;
  7962. }
  7963. }
  7964. // If the scope starts with :: then search from the global scope
  7965. if (currScope.GetLength() < 2 || currScope[0] != ':')
  7966. {
  7967. if (nsName != "")
  7968. {
  7969. if (currNamespace->name != "")
  7970. nsName = currNamespace->name + "::" + nsName;
  7971. }
  7972. else
  7973. nsName = currNamespace->name;
  7974. }
  7975. else
  7976. nsName = nsName.SubString(2);
  7977. // Get the namespace for this scope
  7978. asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf());
  7979. if (ns)
  7980. {
  7981. // Is there a type with typeName in the namespace?
  7982. asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0);
  7983. // Check if the symbol is a member of that type
  7984. if (scopeType)
  7985. {
  7986. // Is it an object type?
  7987. if (CastToObjectType(scopeType))
  7988. {
  7989. SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult);
  7990. if (r != 0)
  7991. return r;
  7992. }
  7993. // Is it an enum type?
  7994. if (CastToEnumType(scopeType))
  7995. {
  7996. asDWORD value = 0;
  7997. asCDataType dt;
  7998. if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value))
  7999. {
  8000. // an enum value was resolved
  8001. outResult->type.SetConstantDW(dt, value);
  8002. outResult->symbolNamespace = ns;
  8003. return SL_ENUMVAL;
  8004. }
  8005. }
  8006. }
  8007. }
  8008. // Get the namespace for this scope. This may return null if the scope is an enum
  8009. nsName = currScope;
  8010. // If the scope starts with :: then search from the global scope
  8011. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8012. {
  8013. if (nsName != "")
  8014. {
  8015. if (currNamespace->name != "")
  8016. nsName = currNamespace->name + "::" + nsName;
  8017. }
  8018. else
  8019. nsName = currNamespace->name;
  8020. }
  8021. else
  8022. nsName = nsName.SubString(2);
  8023. ns = engine->FindNameSpace(nsName.AddressOf());
  8024. // Is it a global property?
  8025. if (ns)
  8026. {
  8027. // See if there are any matching global property accessors
  8028. asCExprContext access(engine);
  8029. int r = 0;
  8030. // Indexed property access
  8031. asCExprContext dummyArg(engine);
  8032. r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns);
  8033. if (r == 0)
  8034. {
  8035. // Normal property access
  8036. r = FindPropertyAccessor(name, &access, 0, ns);
  8037. }
  8038. if (r < 0) return SL_ERROR;
  8039. if (access.property_get || access.property_set)
  8040. {
  8041. MergeExprBytecodeAndType(outResult, &access);
  8042. outResult->symbolNamespace = ns;
  8043. return SL_GLOBALPROPACCESS;
  8044. }
  8045. // See if there is any matching global property
  8046. bool isCompiled = true;
  8047. bool isPureConstant = false;
  8048. bool isAppProp = false;
  8049. asQWORD constantValue = 0;
  8050. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8051. if (prop)
  8052. {
  8053. // If the global property is a pure constant
  8054. // we can allow the compiler to optimize it. Pure
  8055. // constants are global constant variables that were
  8056. // initialized by literal constants.
  8057. if (isPureConstant)
  8058. {
  8059. outResult->type.SetConstantData(prop->type, constantValue);
  8060. outResult->symbolNamespace = ns;
  8061. return SL_GLOBALCONST;
  8062. }
  8063. else
  8064. {
  8065. outResult->type.Set(prop->type);
  8066. outResult->symbolNamespace = ns;
  8067. return SL_GLOBALVAR;
  8068. }
  8069. }
  8070. }
  8071. // Is it the name of a global function?
  8072. if (ns)
  8073. {
  8074. asCArray<int> funcs;
  8075. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8076. if (funcs.GetLength() > 0)
  8077. {
  8078. // Defer the evaluation of which function until it is actually used
  8079. // Store the namespace and name of the function for later
  8080. outResult->type.SetUndefinedFuncHandle(engine);
  8081. outResult->methodName = ns ? ns->name + "::" + name : name;
  8082. outResult->symbolNamespace = ns;
  8083. return SL_GLOBALFUNC;
  8084. }
  8085. }
  8086. // Check for type names
  8087. if (ns)
  8088. {
  8089. asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0);
  8090. if (type)
  8091. {
  8092. outResult->type.dataType = asCDataType::CreateType(type, false);
  8093. return SL_GLOBALTYPE;
  8094. }
  8095. }
  8096. // Is it an enum value?
  8097. if (ns && !engine->ep.requireEnumScope)
  8098. {
  8099. // Look for the enum value without explicitly informing the enum type
  8100. asDWORD value = 0;
  8101. asCDataType dt;
  8102. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  8103. if (e)
  8104. {
  8105. if (e == 2)
  8106. {
  8107. // Ambiguous enum value: Save the name for resolution later.
  8108. // The ambiguity could be resolved now, but I hesitate
  8109. // to store too much information in the context.
  8110. outResult->enumValue = name.AddressOf();
  8111. // We cannot set a dummy value because it will pass through
  8112. // cleanly as an integer.
  8113. outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8114. outResult->symbolNamespace = ns;
  8115. return SL_ENUMVAL;
  8116. }
  8117. else
  8118. {
  8119. // an enum value was resolved
  8120. outResult->type.SetConstantDW(dt, value);
  8121. outResult->symbolNamespace = ns;
  8122. return SL_ENUMVAL;
  8123. }
  8124. }
  8125. }
  8126. // If the given scope starts with '::' then the search starts from global scope
  8127. if (scope.GetLength() >= 2 && scope[0] == ':')
  8128. break;
  8129. // Move up to parent namespace
  8130. currNamespace = engine->GetParentNameSpace(currNamespace);
  8131. }
  8132. // The name doesn't match any symbol
  8133. return SL_NOMATCH;
  8134. }
  8135. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType)
  8136. {
  8137. asCExprContext lookupResult(engine);
  8138. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult);
  8139. if (symbolType < 0)
  8140. {
  8141. // Give dummy value
  8142. ctx->type.SetDummy();
  8143. return -1;
  8144. }
  8145. if (symbolType == SL_NOMATCH)
  8146. {
  8147. // Give dummy value
  8148. ctx->type.SetDummy();
  8149. if (!isOptional)
  8150. {
  8151. // No matching symbol
  8152. asCString msg;
  8153. asCString smbl;
  8154. if (scope == "::")
  8155. smbl = scope;
  8156. else if (scope != "")
  8157. smbl = scope + "::";
  8158. smbl += name;
  8159. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  8160. Error(msg, errNode);
  8161. }
  8162. return -1;
  8163. }
  8164. // It is a local variable or parameter?
  8165. if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR )
  8166. {
  8167. // This is not accessible by default arg expressions
  8168. asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables);
  8169. sVariable *v = variables->GetVariable(name.AddressOf());
  8170. asASSERT(v);
  8171. if( v->isPureConstant )
  8172. ctx->type.SetConstantData(v->type, v->constantValue);
  8173. else if( v->type.IsPrimitive() )
  8174. {
  8175. if( v->type.IsReference() )
  8176. {
  8177. // Copy the reference into the register
  8178. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  8179. ctx->bc.Instr(asBC_PopRPtr);
  8180. ctx->type.Set(v->type);
  8181. }
  8182. else
  8183. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8184. // Set as lvalue unless it is a const variable
  8185. if( !v->type.IsReadOnly() )
  8186. ctx->type.isLValue = true;
  8187. }
  8188. else
  8189. {
  8190. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  8191. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8192. // If the variable is allocated on the heap we have a reference,
  8193. // otherwise the actual object pointer is pushed on the stack.
  8194. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  8195. // Implicitly dereference handle parameters sent by reference
  8196. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  8197. ctx->bc.Instr(asBC_RDSPtr);
  8198. // Mark the object as safe for access unless it is a handle, as the
  8199. // life time of the object is guaranteed throughout the scope.
  8200. if( !v->type.IsObjectHandle() )
  8201. ctx->type.isRefSafe = true;
  8202. // Set as lvalue unless it is a const variable
  8203. if (!v->type.IsReadOnly())
  8204. ctx->type.isLValue = true;
  8205. }
  8206. return 0;
  8207. }
  8208. // Is it a class member?
  8209. if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR)
  8210. {
  8211. // This is not accessible by default arg expressions
  8212. asASSERT(!isCompilingDefaultArg);
  8213. if (symbolType == SL_THISPTR)
  8214. {
  8215. asASSERT(name == THIS_TOKEN && !objType && scope == "");
  8216. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8217. // The object pointer is located at stack position 0
  8218. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8219. ctx->type.SetVariable(dt, 0, false);
  8220. ctx->type.dataType.MakeReference(true);
  8221. ctx->type.isLValue = true;
  8222. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  8223. ctx->type.isRefSafe = true;
  8224. return 0;
  8225. }
  8226. if (symbolType == SL_CLASSPROPACCESS)
  8227. {
  8228. if (scope != "")
  8229. {
  8230. // Cannot access non-static members like this
  8231. asCString msg;
  8232. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8233. Error(msg, errNode);
  8234. return -1;
  8235. }
  8236. // See if there are any matching property accessors
  8237. asCExprContext access(engine);
  8238. if (objType)
  8239. access.type.Set(asCDataType::CreateType(objType, false));
  8240. else
  8241. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
  8242. access.type.dataType.MakeReference(true);
  8243. int r = 0;
  8244. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8245. {
  8246. // This is an index access, check if there is a property accessor that takes an index arg
  8247. asCExprContext dummyArg(engine);
  8248. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  8249. }
  8250. if (r == 0)
  8251. {
  8252. // Normal property access
  8253. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  8254. }
  8255. if (r < 0) return -1;
  8256. if (access.property_get == 0 && access.property_set == 0)
  8257. {
  8258. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8259. asCString msg;
  8260. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8261. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8262. else
  8263. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8264. Error(msg, errNode);
  8265. return -1;
  8266. }
  8267. if (!objType)
  8268. {
  8269. // Prepare the bytecode for the member access
  8270. // This is only done when accessing through the implicit this pointer
  8271. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8272. }
  8273. MergeExprBytecodeAndType(ctx, &access);
  8274. return 0;
  8275. }
  8276. if (symbolType == SL_CLASSPROP)
  8277. {
  8278. if (scope != "")
  8279. {
  8280. // Cannot access non-static members like this
  8281. asCString msg;
  8282. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8283. Error(msg, errNode);
  8284. return -1;
  8285. }
  8286. asCDataType dt;
  8287. if (objType)
  8288. dt = asCDataType::CreateType(objType, false);
  8289. else
  8290. dt = asCDataType::CreateType(outFunc->objectType, false);
  8291. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8292. asASSERT(prop);
  8293. // Is the property access allowed?
  8294. if (prop->isPrivate && prop->isInherited)
  8295. {
  8296. if (engine->ep.privatePropAsProtected)
  8297. {
  8298. // The application is allowing inherited classes to access private properties of the parent
  8299. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  8300. // as it was how the compiler behaved earlier.
  8301. asCString msg;
  8302. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  8303. Warning(msg, errNode);
  8304. }
  8305. else
  8306. {
  8307. asCString msg;
  8308. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8309. Error(msg, errNode);
  8310. }
  8311. }
  8312. if (!objType)
  8313. {
  8314. // The object pointer is located at stack position 0
  8315. // This is only done when accessing through the implicit this pointer
  8316. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8317. ctx->type.SetVariable(dt, 0, false);
  8318. ctx->type.dataType.MakeReference(true);
  8319. Dereference(ctx, true);
  8320. }
  8321. // TODO: This is the same as what is in CompileExpressionPostOp
  8322. // Put the offset on the stack
  8323. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  8324. if (prop->type.IsReference())
  8325. ctx->bc.Instr(asBC_RDSPtr);
  8326. // Reference to primitive must be stored in the temp register
  8327. if (prop->type.IsPrimitive())
  8328. {
  8329. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  8330. ctx->bc.Instr(asBC_PopRPtr);
  8331. }
  8332. // Set the new type (keeping info about temp variable)
  8333. ctx->type.dataType = prop->type;
  8334. ctx->type.dataType.MakeReference(true);
  8335. ctx->type.isVariable = false;
  8336. ctx->type.isLValue = true;
  8337. if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())
  8338. {
  8339. // Objects that are members are not references
  8340. ctx->type.dataType.MakeReference(false);
  8341. // Objects that are members but not handles are safe as long as the parent object is safe
  8342. if (!objType || ctx->type.isRefSafe)
  8343. ctx->type.isRefSafe = true;
  8344. }
  8345. else if (ctx->type.dataType.IsObjectHandle())
  8346. {
  8347. // Objects accessed through handles cannot be considered safe
  8348. // as the handle can be cleared at any time
  8349. ctx->type.isRefSafe = false;
  8350. }
  8351. // If the object reference is const, the property will also be const
  8352. ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
  8353. return 0;
  8354. }
  8355. if (symbolType == SL_CLASSMETHOD)
  8356. {
  8357. if (scope != "")
  8358. {
  8359. // Cannot access non-static members like this
  8360. asCString msg;
  8361. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8362. Error(msg, errNode);
  8363. return -1;
  8364. }
  8365. #if AS_DEBUG
  8366. // If it is not a property, it may still be the name of a method which can be used to create delegates
  8367. asCObjectType *ot = outFunc->objectType;
  8368. asCScriptFunction *func = 0;
  8369. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8370. {
  8371. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8372. if (f->name == name &&
  8373. (builder->module->accessMask & f->accessMask))
  8374. {
  8375. func = f;
  8376. break;
  8377. }
  8378. }
  8379. asASSERT(func);
  8380. #endif
  8381. // An object method was found. Keep the name of the method in the expression, but
  8382. // don't actually modify the bytecode at this point since it is not yet known what
  8383. // the method will be used for, or even what overloaded method should be used.
  8384. ctx->methodName = name;
  8385. // Place the object pointer on the stack, as if the expression was this.func
  8386. if (!objType)
  8387. {
  8388. // The object pointer is located at stack position 0
  8389. // This is only done when accessing through the implicit this pointer
  8390. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8391. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  8392. ctx->type.dataType.MakeReference(true);
  8393. Dereference(ctx, true);
  8394. }
  8395. return 0;
  8396. }
  8397. }
  8398. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL)
  8399. {
  8400. // Get the namespace from SymbolLookup
  8401. asSNameSpace *ns = lookupResult.symbolNamespace;
  8402. if (symbolType == SL_GLOBALPROPACCESS)
  8403. {
  8404. // See if there are any matching global property accessors
  8405. asCExprContext access(engine);
  8406. int r = 0;
  8407. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8408. {
  8409. // This is an index access, check if there is a property accessor that takes an index arg
  8410. asCExprContext dummyArg(engine);
  8411. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  8412. }
  8413. if (r == 0)
  8414. {
  8415. // Normal property access
  8416. r = FindPropertyAccessor(name, &access, errNode, ns);
  8417. }
  8418. if (r < 0) return -1;
  8419. if (access.property_get == 0 && access.property_set == 0)
  8420. {
  8421. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8422. asCString msg;
  8423. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8424. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8425. else
  8426. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8427. Error(msg, errNode);
  8428. return -1;
  8429. }
  8430. // Prepare the bytecode for the function call
  8431. MergeExprBytecodeAndType(ctx, &access);
  8432. return 0;
  8433. }
  8434. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR)
  8435. {
  8436. bool isCompiled = true;
  8437. bool isPureConstant = false;
  8438. bool isAppProp = false;
  8439. asQWORD constantValue = 0;
  8440. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8441. asASSERT(prop);
  8442. // Verify that the global property has been compiled already
  8443. if (!isCompiled)
  8444. {
  8445. asCString str;
  8446. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  8447. Error(str, errNode);
  8448. return -1;
  8449. }
  8450. // If the global property is a pure constant
  8451. // we can allow the compiler to optimize it. Pure
  8452. // constants are global constant variables that were
  8453. // initialized by literal constants.
  8454. if (isPureConstant)
  8455. ctx->type.SetConstantData(prop->type, constantValue);
  8456. else
  8457. {
  8458. // A shared type must not access global vars, unless they
  8459. // too are shared, e.g. application registered vars
  8460. if (outFunc->IsShared())
  8461. {
  8462. if (!isAppProp)
  8463. {
  8464. asCString str;
  8465. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  8466. Error(str, errNode);
  8467. // Allow the compilation to continue to catch other problems
  8468. }
  8469. }
  8470. ctx->type.Set(prop->type);
  8471. ctx->type.isLValue = true;
  8472. if (ctx->type.dataType.IsPrimitive())
  8473. {
  8474. // Load the address of the variable into the register
  8475. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  8476. ctx->type.dataType.MakeReference(true);
  8477. }
  8478. else
  8479. {
  8480. // Push the address of the variable on the stack
  8481. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  8482. // If the object is a value type or a non-handle variable to a reference type,
  8483. // then we must validate the existance as it could potentially be accessed
  8484. // before it is initialized.
  8485. // This check is not needed for application registered properties, since they
  8486. // are guaranteed to be valid by the application itself.
  8487. if (!isAppProp &&
  8488. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8489. !ctx->type.dataType.IsObjectHandle()))
  8490. {
  8491. ctx->bc.Instr(asBC_ChkRefS);
  8492. }
  8493. // If the address pushed on the stack is to a value type or an object
  8494. // handle, then mark the expression as a reference. Addresses to a reference
  8495. // type aren't marked as references to get correct behaviour
  8496. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8497. ctx->type.dataType.IsObjectHandle())
  8498. {
  8499. ctx->type.dataType.MakeReference(true);
  8500. }
  8501. else
  8502. {
  8503. asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle());
  8504. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  8505. ctx->bc.Instr(asBC_RDSPtr);
  8506. }
  8507. }
  8508. }
  8509. return 0;
  8510. }
  8511. if (symbolType == SL_GLOBALFUNC)
  8512. {
  8513. asCArray<int> funcs;
  8514. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8515. asASSERT(funcs.GetLength() > 0);
  8516. if (funcs.GetLength() > 0)
  8517. {
  8518. // Defer the evaluation of which function until it is actually used
  8519. // Store the namespace and name of the function for later
  8520. ctx->type.SetUndefinedFuncHandle(engine);
  8521. ctx->methodName = ns ? ns->name + "::" + name : name;
  8522. }
  8523. return 0;
  8524. }
  8525. if (symbolType == SL_ENUMVAL)
  8526. {
  8527. // The enum type and namespace must be returned from SymbolLookup
  8528. asCDataType dt = lookupResult.type.dataType;
  8529. if (!dt.IsEnumType())
  8530. {
  8531. asASSERT(!engine->ep.requireEnumScope);
  8532. // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known
  8533. ctx->enumValue = name.AddressOf();
  8534. ctx->symbolNamespace = lookupResult.symbolNamespace;
  8535. // We cannot set a dummy value because it will pass through
  8536. // cleanly as an integer.
  8537. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8538. return 0;
  8539. }
  8540. asDWORD value = 0;
  8541. builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
  8542. // Even if the enum type is not shared, and we're compiling a shared object,
  8543. // the use of the values are still allowed, since they are treated as constants.
  8544. // an enum value was resolved
  8545. ctx->type.SetConstantDW(dt, value);
  8546. return 0;
  8547. }
  8548. }
  8549. // The result must have been identified above
  8550. if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE)
  8551. {
  8552. // Give dummy value
  8553. ctx->type.SetDummy();
  8554. // The symbol matches a type
  8555. asCString msg;
  8556. asCString smbl;
  8557. if (scope == "::")
  8558. smbl = scope;
  8559. else if (scope != "")
  8560. smbl = scope + "::";
  8561. smbl += name;
  8562. msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf());
  8563. Error(msg, errNode);
  8564. return -1;
  8565. }
  8566. // Should not come here
  8567. asASSERT(false);
  8568. return 0;
  8569. }
  8570. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  8571. {
  8572. // Shouldn't receive any byte code
  8573. asASSERT(ctx->bc.GetLastInstr() == -1);
  8574. asCScriptNode *vnode = node->firstChild;
  8575. ctx->exprNode = vnode;
  8576. if( vnode->nodeType == snVariableAccess )
  8577. {
  8578. // Determine the scope resolution of the variable
  8579. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  8580. // Determine the name of the variable
  8581. asASSERT(vnode->nodeType == snIdentifier );
  8582. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  8583. return CompileVariableAccess(name, scope, ctx, node);
  8584. }
  8585. else if( vnode->nodeType == snConstant )
  8586. {
  8587. if( vnode->tokenType == ttIntConstant )
  8588. {
  8589. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8590. bool overflow = false;
  8591. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  8592. // Is the number bigger than a 64bit word?
  8593. if (overflow)
  8594. {
  8595. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8596. // Set the value to zero to avoid further warnings
  8597. val = 0;
  8598. }
  8599. // Do we need 64 bits?
  8600. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  8601. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  8602. if( val>>31 )
  8603. {
  8604. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  8605. if( val>>63 )
  8606. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8607. else
  8608. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  8609. }
  8610. else
  8611. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  8612. }
  8613. else if( vnode->tokenType == ttBitsConstant )
  8614. {
  8615. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8616. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  8617. bool overflow = false;
  8618. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  8619. // Is the number bigger than a 64bit word?
  8620. if (overflow)
  8621. {
  8622. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8623. // Set the value to zero to avoid further warnings
  8624. val = 0;
  8625. }
  8626. // Do we need 64 bits?
  8627. if( val>>32 )
  8628. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8629. else
  8630. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  8631. }
  8632. else if( vnode->tokenType == ttFloatConstant )
  8633. {
  8634. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8635. // TODO: Check for overflow
  8636. size_t numScanned;
  8637. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  8638. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  8639. #ifndef AS_USE_DOUBLE_AS_FLOAT
  8640. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  8641. asASSERT(numScanned == vnode->tokenLength - 1);
  8642. #endif
  8643. }
  8644. else if( vnode->tokenType == ttDoubleConstant )
  8645. {
  8646. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8647. // TODO: Check for overflow
  8648. size_t numScanned;
  8649. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  8650. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  8651. asASSERT(numScanned == vnode->tokenLength);
  8652. }
  8653. else if( vnode->tokenType == ttTrue ||
  8654. vnode->tokenType == ttFalse )
  8655. {
  8656. #if AS_SIZEOF_BOOL == 1
  8657. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8658. #else
  8659. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8660. #endif
  8661. }
  8662. else if( vnode->tokenType == ttStringConstant ||
  8663. vnode->tokenType == ttMultilineStringConstant ||
  8664. vnode->tokenType == ttHeredocStringConstant )
  8665. {
  8666. asCString str;
  8667. asCScriptNode *snode = vnode->firstChild;
  8668. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  8669. {
  8670. // Treat the single quoted string as a single character literal
  8671. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8672. asDWORD val = 0;
  8673. if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
  8674. {
  8675. // This is the start of a UTF8 encoded character. We need to decode it
  8676. val = asStringDecodeUTF8(str.AddressOf(), 0);
  8677. if( val == (asDWORD)-1 )
  8678. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8679. }
  8680. else
  8681. {
  8682. val = ProcessStringConstant(str, snode);
  8683. if( val == (asDWORD)-1 )
  8684. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8685. }
  8686. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  8687. }
  8688. else
  8689. {
  8690. // Process the string constants
  8691. while( snode )
  8692. {
  8693. asCString cat;
  8694. if( snode->tokenType == ttStringConstant )
  8695. {
  8696. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8697. ProcessStringConstant(cat, snode);
  8698. }
  8699. else if( snode->tokenType == ttMultilineStringConstant )
  8700. {
  8701. if( !engine->ep.allowMultilineStrings )
  8702. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  8703. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8704. ProcessStringConstant(cat, snode);
  8705. }
  8706. else if( snode->tokenType == ttHeredocStringConstant )
  8707. {
  8708. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  8709. ProcessHeredocStringConstant(cat, snode);
  8710. }
  8711. str += cat;
  8712. snode = snode->next;
  8713. }
  8714. // Call the string factory function to create a string object
  8715. if(engine->stringFactory == 0 )
  8716. {
  8717. // Error
  8718. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  8719. // Give dummy value
  8720. ctx->type.SetDummy();
  8721. return -1;
  8722. }
  8723. else
  8724. {
  8725. void *strPtr = const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
  8726. if (strPtr == 0)
  8727. {
  8728. // TODO: A better message is needed
  8729. Error(TXT_NULL_POINTER_ACCESS, vnode);
  8730. ctx->type.SetDummy();
  8731. return -1;
  8732. }
  8733. // Keep the pointer in the list for clean up at exit
  8734. usedStringConstants.PushLast(strPtr);
  8735. // Push the pointer on the stack. The string factory already guarantees that the
  8736. // string object is valid throughout the lifetime of the script so no need to add
  8737. // reference count or make local copy.
  8738. ctx->bc.InstrPTR(asBC_PGA, strPtr);
  8739. ctx->type.Set(engine->stringType);
  8740. // Mark the string as literal constant so the compiler knows it is allowed
  8741. // to treat it differently than an ordinary constant string variable
  8742. ctx->type.isConstant = true;
  8743. // Mark the reference to the string constant as safe, so the compiler can
  8744. // avoid making unnecessary temporary copies when passing the reference to
  8745. // functions.
  8746. ctx->type.isRefSafe = true;
  8747. }
  8748. }
  8749. }
  8750. else if( vnode->tokenType == ttNull )
  8751. {
  8752. ctx->bc.Instr(asBC_PshNull);
  8753. ctx->type.SetNullConstant();
  8754. }
  8755. else
  8756. asASSERT(false);
  8757. }
  8758. else if( vnode->nodeType == snFunctionCall )
  8759. {
  8760. // Determine the scope resolution
  8761. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  8762. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  8763. }
  8764. else if( vnode->nodeType == snConstructCall )
  8765. {
  8766. return CompileConstructCall(vnode, ctx);
  8767. }
  8768. else if( vnode->nodeType == snAssignment )
  8769. {
  8770. asCExprContext e(engine);
  8771. int r = CompileAssignment(vnode, &e);
  8772. if( r < 0 )
  8773. {
  8774. ctx->type.SetDummy();
  8775. return r;
  8776. }
  8777. MergeExprBytecodeAndType(ctx, &e);
  8778. }
  8779. else if( vnode->nodeType == snCast )
  8780. {
  8781. // Implement the cast operator
  8782. return CompileConversion(vnode, ctx);
  8783. }
  8784. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  8785. {
  8786. // This is a void expression
  8787. ctx->SetVoidExpression();
  8788. }
  8789. else if( vnode->nodeType == snFunction )
  8790. {
  8791. // This is an anonymous function
  8792. // Defer the evaluation of the function until it is known where it
  8793. // will be used, which is where the signature will be defined
  8794. ctx->SetLambda(vnode);
  8795. }
  8796. else
  8797. asASSERT(false);
  8798. return 0;
  8799. }
  8800. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  8801. {
  8802. int charLiteral = -1;
  8803. // Process escape sequences
  8804. asCArray<char> str((int)cstr.GetLength());
  8805. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  8806. {
  8807. #ifdef AS_DOUBLEBYTE_CHARSET
  8808. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  8809. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  8810. {
  8811. // This is the lead character of a double byte character
  8812. // include the trail character without checking it's value.
  8813. str.PushLast(cstr[n]);
  8814. n++;
  8815. str.PushLast(cstr[n]);
  8816. continue;
  8817. }
  8818. #endif
  8819. asUINT val;
  8820. if( processEscapeSequences && cstr[n] == '\\' )
  8821. {
  8822. ++n;
  8823. if( n == cstr.GetLength() )
  8824. {
  8825. if( charLiteral == -1 ) charLiteral = 0;
  8826. return charLiteral;
  8827. }
  8828. // Hexadecimal escape sequences will allow the construction of
  8829. // invalid unicode sequences, but the string should also work as
  8830. // a bytearray so we must support this. The code for working with
  8831. // unicode text must be prepared to handle invalid unicode sequences
  8832. if( cstr[n] == 'x' || cstr[n] == 'X' )
  8833. {
  8834. ++n;
  8835. if( n == cstr.GetLength() ) break;
  8836. val = 0;
  8837. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  8838. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  8839. {
  8840. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8841. val = val*16 + cstr[n] - '0';
  8842. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8843. val = val*16 + cstr[n] - 'a' + 10;
  8844. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8845. val = val*16 + cstr[n] - 'A' + 10;
  8846. else
  8847. break;
  8848. }
  8849. // Rewind one, since the loop will increment it again
  8850. n--;
  8851. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  8852. if( engine->ep.stringEncoding == 0 )
  8853. {
  8854. str.PushLast((asBYTE)val);
  8855. }
  8856. else
  8857. {
  8858. #ifndef AS_BIG_ENDIAN
  8859. str.PushLast((asBYTE)val);
  8860. str.PushLast((asBYTE)(val>>8));
  8861. #else
  8862. str.PushLast((asBYTE)(val>>8));
  8863. str.PushLast((asBYTE)val);
  8864. #endif
  8865. }
  8866. if( charLiteral == -1 ) charLiteral = val;
  8867. continue;
  8868. }
  8869. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  8870. {
  8871. // \u expects 4 hex digits
  8872. // \U expects 8 hex digits
  8873. bool expect2 = cstr[n] == 'u';
  8874. int c = expect2 ? 4 : 8;
  8875. val = 0;
  8876. for( ; c > 0; c-- )
  8877. {
  8878. ++n;
  8879. if( n == cstr.GetLength() ) break;
  8880. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8881. val = val*16 + cstr[n] - '0';
  8882. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8883. val = val*16 + cstr[n] - 'a' + 10;
  8884. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8885. val = val*16 + cstr[n] - 'A' + 10;
  8886. else
  8887. break;
  8888. }
  8889. if( c != 0 )
  8890. {
  8891. // Give warning about invalid code point
  8892. // TODO: Need code position for warning
  8893. asCString msg;
  8894. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  8895. Warning(msg, node);
  8896. continue;
  8897. }
  8898. }
  8899. else
  8900. {
  8901. if( cstr[n] == '"' )
  8902. val = '"';
  8903. else if( cstr[n] == '\'' )
  8904. val = '\'';
  8905. else if( cstr[n] == 'n' )
  8906. val = '\n';
  8907. else if( cstr[n] == 'r' )
  8908. val = '\r';
  8909. else if( cstr[n] == 't' )
  8910. val = '\t';
  8911. else if( cstr[n] == '0' )
  8912. val = '\0';
  8913. else if( cstr[n] == '\\' )
  8914. val = '\\';
  8915. else
  8916. {
  8917. // Invalid escape sequence
  8918. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  8919. continue;
  8920. }
  8921. }
  8922. }
  8923. else
  8924. {
  8925. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  8926. {
  8927. unsigned int len;
  8928. val = asStringDecodeUTF8(&cstr[n], &len);
  8929. if( val == 0xFFFFFFFF )
  8930. {
  8931. // Incorrect UTF8 encoding. Use only the first byte
  8932. // TODO: Need code position for warning
  8933. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  8934. val = (unsigned char)cstr[n];
  8935. }
  8936. else
  8937. n += len-1;
  8938. }
  8939. else
  8940. val = (unsigned char)cstr[n];
  8941. }
  8942. // Add the character to the final string
  8943. char encodedValue[5];
  8944. int len;
  8945. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  8946. {
  8947. // Convert to UTF8 encoded
  8948. len = asStringEncodeUTF8(val, encodedValue);
  8949. }
  8950. else if( engine->ep.stringEncoding == 1 )
  8951. {
  8952. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  8953. len = asStringEncodeUTF16(val, encodedValue);
  8954. }
  8955. else
  8956. {
  8957. // Do not convert ASCII characters
  8958. encodedValue[0] = (asBYTE)val;
  8959. len = 1;
  8960. }
  8961. if( len < 0 )
  8962. {
  8963. // Give warning about invalid code point
  8964. // TODO: Need code position for warning
  8965. Warning(TXT_INVALID_UNICODE_VALUE, node);
  8966. }
  8967. else
  8968. {
  8969. // Add the encoded value to the final string
  8970. str.Concatenate(encodedValue, len);
  8971. if( charLiteral == -1 ) charLiteral = val;
  8972. }
  8973. }
  8974. cstr.Assign(str.AddressOf(), str.GetLength());
  8975. return charLiteral;
  8976. }
  8977. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  8978. {
  8979. // Remove first line if it only contains whitespace
  8980. bool isMultiline = false;
  8981. int start;
  8982. for( start = 0; start < (int)str.GetLength(); start++ )
  8983. {
  8984. if( str[start] == '\n' )
  8985. {
  8986. isMultiline = true;
  8987. // Remove the linebreak as well
  8988. start++;
  8989. break;
  8990. }
  8991. if( str[start] != ' ' &&
  8992. str[start] != '\t' &&
  8993. str[start] != '\r' )
  8994. {
  8995. // Don't remove anything
  8996. start = 0;
  8997. break;
  8998. }
  8999. }
  9000. // Remove the line after the last line break if it only contains whitespaces
  9001. int end;
  9002. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  9003. {
  9004. if( str[end] == '\n' )
  9005. {
  9006. // Don't remove the last line break
  9007. end++;
  9008. break;
  9009. }
  9010. if( str[end] != ' ' &&
  9011. str[end] != '\t' &&
  9012. str[end] != '\r' )
  9013. {
  9014. // Don't remove anything
  9015. end = (int)str.GetLength();
  9016. break;
  9017. }
  9018. }
  9019. if( end < 0 ) end = 0;
  9020. asCString tmp;
  9021. if (end > start || engine->ep.heredocTrimMode != 2 )
  9022. {
  9023. // if heredocTrimMode == 0 the string shouldn't be trimmed
  9024. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  9025. // if heredocTrimMode == 2 the string should always be trimmed
  9026. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  9027. tmp.Assign(&str[start], end - start);
  9028. else
  9029. tmp = str;
  9030. }
  9031. ProcessStringConstant(tmp, node, false);
  9032. str = tmp;
  9033. }
  9034. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  9035. {
  9036. asCExprContext expr(engine);
  9037. asCDataType to;
  9038. bool anyErrors = false;
  9039. EImplicitConv convType;
  9040. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  9041. {
  9042. convType = asIC_EXPLICIT_VAL_CAST;
  9043. // Verify that there is only one argument
  9044. if( node->lastChild->firstChild == 0 ||
  9045. node->lastChild->firstChild != node->lastChild->lastChild )
  9046. {
  9047. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  9048. expr.type.SetDummy();
  9049. anyErrors = true;
  9050. }
  9051. else if (node->lastChild->firstChild &&
  9052. node->lastChild->firstChild->nodeType == snNamedArgument)
  9053. {
  9054. Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
  9055. expr.type.SetDummy();
  9056. anyErrors = true;
  9057. }
  9058. else
  9059. {
  9060. // Compile the expression
  9061. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  9062. if( r < 0 )
  9063. anyErrors = true;
  9064. }
  9065. // Determine the requested type
  9066. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9067. to.MakeReadOnly(true); // Default to const
  9068. asASSERT(to.IsPrimitive());
  9069. }
  9070. else
  9071. {
  9072. convType = asIC_EXPLICIT_REF_CAST;
  9073. // Compile the expression
  9074. int r = CompileAssignment(node->lastChild, &expr);
  9075. if( r < 0 )
  9076. anyErrors = true;
  9077. // Determine the requested type
  9078. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9079. // If the type support object handles, then use it
  9080. if( to.SupportHandles() )
  9081. {
  9082. to.MakeHandle(true);
  9083. if( expr.type.dataType.IsObjectConst() )
  9084. to.MakeHandleToConst(true);
  9085. }
  9086. else if( !to.IsObjectHandle() )
  9087. {
  9088. // The cast<type> operator can only be used for reference casts
  9089. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  9090. anyErrors = true;
  9091. }
  9092. }
  9093. // Do not allow casting to non shared type if we're compiling a shared method
  9094. if( outFunc->IsShared() &&
  9095. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  9096. {
  9097. asCString msg;
  9098. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  9099. Error(msg, node);
  9100. anyErrors = true;
  9101. }
  9102. if( anyErrors )
  9103. {
  9104. // Assume that the error can be fixed and allow the compilation to continue
  9105. ctx->type.Set(to);
  9106. return -1;
  9107. }
  9108. ProcessPropertyGetAccessor(&expr, node);
  9109. // Don't allow any operators on expressions that take address of class method
  9110. if( expr.IsClassMethod() )
  9111. {
  9112. Error(TXT_INVALID_OP_ON_METHOD, node);
  9113. return -1;
  9114. }
  9115. // We don't want a reference for conversion casts
  9116. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  9117. {
  9118. if( expr.type.dataType.IsObject() )
  9119. Dereference(&expr, true);
  9120. else
  9121. ConvertToVariable(&expr);
  9122. }
  9123. ImplicitConversion(&expr, to, node, convType);
  9124. IsVariableInitialized(&expr.type, node);
  9125. // If no type conversion is really tried ignore it
  9126. if( to == expr.type.dataType )
  9127. {
  9128. // This will keep information about constant type
  9129. MergeExprBytecode(ctx, &expr);
  9130. ctx->type = expr.type;
  9131. return 0;
  9132. }
  9133. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  9134. {
  9135. MergeExprBytecode(ctx, &expr);
  9136. ctx->type = expr.type;
  9137. ctx->type.dataType.MakeReadOnly(true);
  9138. return 0;
  9139. }
  9140. // The implicit conversion already does most of the conversions permitted,
  9141. // here we'll only treat those conversions that require an explicit cast.
  9142. bool conversionOK = false;
  9143. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  9144. {
  9145. if( !expr.type.dataType.IsObject() )
  9146. ConvertToTempVariable(&expr);
  9147. if( to.IsObjectHandle() &&
  9148. expr.type.dataType.IsObjectHandle() &&
  9149. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  9150. {
  9151. conversionOK = CompileRefCast(&expr, to, true, node);
  9152. MergeExprBytecode(ctx, &expr);
  9153. ctx->type = expr.type;
  9154. }
  9155. }
  9156. if( conversionOK )
  9157. return 0;
  9158. // Conversion not available
  9159. ctx->type.SetDummy();
  9160. asCString strTo, strFrom;
  9161. strTo = to.Format(outFunc->nameSpace);
  9162. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  9163. asCString msg;
  9164. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  9165. Error(msg, node);
  9166. return -1;
  9167. }
  9168. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  9169. {
  9170. // deferAll is set to true if for example the function returns a reference, since in
  9171. // this case the function might be returning a reference to one of the arguments.
  9172. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  9173. // Parameters that are sent by reference should be assigned
  9174. // to the evaluated expression if it is an lvalue
  9175. // Evaluate the arguments from last to first
  9176. int n = (int)descr->parameterTypes.GetLength() - 1;
  9177. for( ; n >= 0; n-- )
  9178. {
  9179. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  9180. // If deferAll is set all objects passed by reference or handle must be deferred
  9181. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  9182. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  9183. {
  9184. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  9185. // For &inout, only store the argument if it is for a temporary variable
  9186. if( engine->ep.allowUnsafeReferences ||
  9187. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  9188. {
  9189. // Store the argument for later processing
  9190. asSDeferredParam outParam;
  9191. outParam.argNode = args[n]->exprNode;
  9192. outParam.argType = args[n]->type;
  9193. outParam.argInOutFlags = descr->inOutFlags[n];
  9194. outParam.origExpr = args[n]->origExpr;
  9195. ctx->deferredParams.PushLast(outParam);
  9196. }
  9197. }
  9198. else
  9199. {
  9200. // Release the temporary variable now
  9201. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  9202. }
  9203. // Move the argument's deferred expressions over to the final expression
  9204. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  9205. {
  9206. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  9207. args[n]->deferredParams[m].origExpr = 0;
  9208. }
  9209. args[n]->deferredParams.SetLength(0);
  9210. }
  9211. }
  9212. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  9213. {
  9214. if( isProcessingDeferredParams ) return;
  9215. isProcessingDeferredParams = true;
  9216. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  9217. {
  9218. asSDeferredParam outParam = ctx->deferredParams[n];
  9219. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  9220. {
  9221. // Just release the variable
  9222. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9223. }
  9224. else if( outParam.argInOutFlags == asTM_OUTREF )
  9225. {
  9226. asCExprContext *expr = outParam.origExpr;
  9227. outParam.origExpr = 0;
  9228. if( outParam.argType.dataType.IsObjectHandle() )
  9229. {
  9230. // Implicitly convert the value to a handle
  9231. if( expr->type.dataType.IsObjectHandle() )
  9232. expr->type.isExplicitHandle = true;
  9233. }
  9234. // Verify that the expression result in a lvalue, or a property accessor
  9235. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  9236. {
  9237. asCExprContext rctx(engine);
  9238. rctx.type = outParam.argType;
  9239. if( rctx.type.dataType.IsPrimitive() )
  9240. rctx.type.dataType.MakeReference(false);
  9241. else
  9242. {
  9243. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  9244. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  9245. if( expr->type.isExplicitHandle )
  9246. rctx.type.isExplicitHandle = true;
  9247. }
  9248. asCExprContext o(engine);
  9249. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  9250. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  9251. // The assignment may itself have resulted in a new temporary variable, e.g. if
  9252. // the opAssign returns a non-reference. We must release this temporary variable
  9253. // since it won't be used
  9254. ReleaseTemporaryVariable(o.type, &o.bc);
  9255. MergeExprBytecode(ctx, &o);
  9256. }
  9257. else
  9258. {
  9259. // We must still evaluate the expression
  9260. MergeExprBytecode(ctx, expr);
  9261. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  9262. ctx->bc.Instr(asBC_PopPtr);
  9263. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  9264. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() &&
  9265. !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) )
  9266. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  9267. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9268. }
  9269. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  9270. // Delete the original expression context
  9271. asDELETE(expr, asCExprContext);
  9272. }
  9273. else // &inout
  9274. {
  9275. if( outParam.argType.isTemporary )
  9276. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9277. else if( !outParam.argType.isVariable )
  9278. {
  9279. if( outParam.argType.dataType.IsObject() &&
  9280. ((outParam.argType.dataType.GetBehaviour()->addref &&
  9281. outParam.argType.dataType.GetBehaviour()->release) ||
  9282. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  9283. {
  9284. // Release the object handle that was taken to guarantee the reference
  9285. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9286. }
  9287. }
  9288. }
  9289. }
  9290. ctx->deferredParams.SetLength(0);
  9291. isProcessingDeferredParams = false;
  9292. }
  9293. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  9294. {
  9295. // The first node is a datatype node
  9296. asCString name;
  9297. asCExprValue tempObj;
  9298. bool onHeap = true;
  9299. asCArray<int> funcs;
  9300. bool error = false;
  9301. // It is possible that the name is really a constructor
  9302. asCDataType dt;
  9303. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9304. if( dt.IsPrimitive() )
  9305. {
  9306. // This is a cast to a primitive type
  9307. return CompileConversion(node, ctx);
  9308. }
  9309. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  9310. {
  9311. // Types declared as implicit handle must not attempt to construct a handle
  9312. dt.MakeHandle(false);
  9313. }
  9314. // Don't accept syntax like object@(expr)
  9315. if( dt.IsObjectHandle() )
  9316. {
  9317. asCString str;
  9318. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  9319. Error(str, node);
  9320. ctx->type.SetDummy();
  9321. return -1;
  9322. }
  9323. // Make sure the desired type can actually be instantiated
  9324. // Delegates are allowed to be created through construct calls,
  9325. // even though they cannot be instantiated as variables
  9326. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  9327. {
  9328. asCString str;
  9329. if( dt.IsAbstractClass() )
  9330. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9331. else if( dt.IsInterface() )
  9332. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9333. else
  9334. // TODO: Improve error message to explain why
  9335. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  9336. Error(str, node);
  9337. ctx->type.SetDummy();
  9338. return -1;
  9339. }
  9340. // Do not allow constructing non-shared types in shared functions
  9341. if( outFunc->IsShared() &&
  9342. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  9343. {
  9344. asCString msg;
  9345. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  9346. Error(msg, node);
  9347. return -1;
  9348. }
  9349. // Compile the arguments
  9350. asCArray<asCExprContext *> args;
  9351. asCArray<asSNamedArgument> namedArgs;
  9352. asCArray<asCExprValue> temporaryVariables;
  9353. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9354. {
  9355. // Check for a value cast behaviour
  9356. if( args.GetLength() == 1 )
  9357. {
  9358. asCExprContext conv(engine);
  9359. conv.type = args[0]->type;
  9360. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  9361. // Don't use this if the cost is 0 because it would mean that nothing
  9362. // is done and the script wants a new value to be constructed
  9363. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  9364. {
  9365. // Make sure the result is a reference, just as if to a local variable
  9366. dt.MakeReference(true);
  9367. // Make sure any property accessor is already evaluated
  9368. ProcessPropertyGetAccessor(args[0], args[0]->exprNode);
  9369. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  9370. ctx->bc.AddCode(&args[0]->bc);
  9371. ctx->type = args[0]->type;
  9372. asDELETE(args[0], asCExprContext);
  9373. return 0;
  9374. }
  9375. }
  9376. // Check for possible constructor/factory
  9377. name = dt.Format(outFunc->nameSpace);
  9378. asSTypeBehaviour *beh = dt.GetBehaviour();
  9379. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  9380. {
  9381. funcs = beh->constructors;
  9382. // Value types and script types are allocated through the constructor
  9383. tempObj.dataType = dt;
  9384. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  9385. tempObj.dataType.MakeReference(true);
  9386. tempObj.isTemporary = true;
  9387. tempObj.isVariable = true;
  9388. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  9389. // Push the address of the object on the stack
  9390. if( onHeap )
  9391. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  9392. }
  9393. else if( beh )
  9394. funcs = beh->factories;
  9395. // Special case: Allow calling func(void) with a void expression.
  9396. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  9397. {
  9398. // Evaluate the expression before the function call
  9399. MergeExprBytecode(ctx, args[0]);
  9400. asDELETE(args[0], asCExprContext);
  9401. args.SetLength(0);
  9402. }
  9403. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  9404. // If none has been registered, just allocate the variable and push it on the stack.
  9405. if( args.GetLength() == 0 )
  9406. {
  9407. beh = tempObj.dataType.GetBehaviour();
  9408. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9409. {
  9410. // Call the default constructor
  9411. ctx->type = tempObj;
  9412. if( onHeap )
  9413. {
  9414. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  9415. ctx->bc.RemoveLastInstr();
  9416. }
  9417. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  9418. // Push the reference on the stack
  9419. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9420. return 0;
  9421. }
  9422. }
  9423. // Special case: If this is a construction of a delegate and the expression names an object method
  9424. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  9425. {
  9426. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  9427. // case no object delegate will be created, but instead a delegate for a function pointer
  9428. // In theory a simple cast would be good in this case, but this is a construct call so it
  9429. // is expected that a new object is created.
  9430. dt.MakeHandle(true);
  9431. ctx->type.Set(dt);
  9432. // The delegate must be able to hold on to a reference to the object
  9433. if( !args[0]->type.dataType.SupportHandles() )
  9434. {
  9435. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  9436. error = true;
  9437. }
  9438. else
  9439. {
  9440. // Filter the available object methods to find the one that matches the func def
  9441. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  9442. asCScriptFunction *bestMethod = 0;
  9443. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  9444. {
  9445. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  9446. if( func->name != args[0]->methodName )
  9447. continue;
  9448. // If the expression is for a const object, then only const methods should be accepted
  9449. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  9450. continue;
  9451. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  9452. {
  9453. bestMethod = func;
  9454. // If the expression is non-const the non-const overloaded method has priority
  9455. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  9456. break;
  9457. }
  9458. }
  9459. if( bestMethod )
  9460. {
  9461. // The object pointer is already on the stack
  9462. MergeExprBytecode(ctx, args[0]);
  9463. // Push the function pointer as an additional argument
  9464. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  9465. // Call the factory function for the delegate
  9466. asCArray<int> delegateFuncs;
  9467. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  9468. asASSERT(delegateFuncs.GetLength() == 1 );
  9469. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  9470. // Store the returned delegate in a temporary variable
  9471. int returnOffset = AllocateVariable(dt, true, false);
  9472. dt.MakeReference(true);
  9473. ctx->type.SetVariable(dt, returnOffset, true);
  9474. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9475. // Push a reference to the temporary variable on the stack
  9476. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9477. // Clean up arguments
  9478. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  9479. }
  9480. else
  9481. {
  9482. asCString msg;
  9483. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  9484. Error(msg.AddressOf(), node);
  9485. error = true;
  9486. }
  9487. }
  9488. // Clean-up arg
  9489. asDELETE(args[0], asCExprContext);
  9490. return error ? -1 : 0;
  9491. }
  9492. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  9493. if( funcs.GetLength() != 1 )
  9494. {
  9495. // The error was reported by MatchFunctions()
  9496. error = true;
  9497. // Dummy value
  9498. ctx->type.SetDummy();
  9499. }
  9500. else
  9501. {
  9502. // TODO: Clean up: Merge this with MakeFunctionCall
  9503. // Add the default values for arguments not explicitly supplied
  9504. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  9505. if( r == asSUCCESS )
  9506. {
  9507. asCByteCode objBC(engine);
  9508. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  9509. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  9510. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9511. {
  9512. // If the object is allocated on the stack, then call the constructor as a normal function
  9513. if( onHeap )
  9514. {
  9515. int offset = 0;
  9516. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  9517. for( asUINT n = 0; n < args.GetLength(); n++ )
  9518. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  9519. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  9520. }
  9521. else
  9522. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9523. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  9524. // Add tag that the object has been initialized
  9525. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  9526. // The constructor doesn't return anything,
  9527. // so we have to manually inform the type of
  9528. // the return value
  9529. ctx->type = tempObj;
  9530. if( !onHeap )
  9531. ctx->type.dataType.MakeReference(false);
  9532. // Push the address of the object on the stack again
  9533. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9534. }
  9535. else
  9536. {
  9537. // Call the factory to create the reference type
  9538. PerformFunctionCall(funcs[0], ctx, false, &args);
  9539. }
  9540. }
  9541. else
  9542. error = true;
  9543. }
  9544. }
  9545. else
  9546. {
  9547. // Failed to compile the argument list, set the result to the dummy type
  9548. ctx->type.SetDummy();
  9549. error = true;
  9550. }
  9551. // Cleanup
  9552. for( asUINT n = 0; n < args.GetLength(); n++ )
  9553. if( args[n] )
  9554. {
  9555. asDELETE(args[n], asCExprContext);
  9556. }
  9557. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9558. if( namedArgs[n].ctx )
  9559. {
  9560. asDELETE(namedArgs[n].ctx, asCExprContext);
  9561. }
  9562. return error ? -1 : 0;
  9563. }
  9564. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  9565. {
  9566. asCExprValue tempObj;
  9567. asCArray<int> funcs;
  9568. int localVar = -1;
  9569. bool initializeMembers = false;
  9570. asCExprContext funcExpr(engine);
  9571. asCScriptNode *nm = node->lastChild->prev;
  9572. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  9573. // Find the matching entities
  9574. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  9575. asCExprContext lookupResult(engine);
  9576. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult);
  9577. if (symbolType < 0)
  9578. return -1;
  9579. if (symbolType == SL_NOMATCH)
  9580. {
  9581. // No matching symbol
  9582. asCString msg;
  9583. asCString smbl;
  9584. if (scope == "::")
  9585. smbl = scope;
  9586. else if (scope != "")
  9587. smbl = scope + "::";
  9588. smbl += name;
  9589. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  9590. Error(msg, node);
  9591. return -1;
  9592. }
  9593. // Is the symbol matching a variable/property?
  9594. if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ||
  9595. symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP ||
  9596. symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL)
  9597. {
  9598. // Variables/properties can be used as functions if they have the opCall
  9599. if (!(lookupResult.type.dataType.IsFuncdef() || lookupResult.type.dataType.IsObject()))
  9600. {
  9601. // The variable is not a function or object with opCall
  9602. asCString msg;
  9603. msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf());
  9604. Error(msg, node);
  9605. return -1;
  9606. }
  9607. // Compile the variable
  9608. // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
  9609. localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
  9610. asASSERT(localVar >= 0);
  9611. if( localVar < 0 )
  9612. return -1;
  9613. if (funcExpr.type.dataType.IsFuncdef())
  9614. {
  9615. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  9616. }
  9617. else if (funcExpr.type.dataType.IsObject())
  9618. {
  9619. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  9620. if (ctx->type.isTemporary)
  9621. {
  9622. asASSERT(objectType);
  9623. asSDeferredParam deferred;
  9624. deferred.origExpr = 0;
  9625. deferred.argInOutFlags = asTM_INREF;
  9626. deferred.argNode = 0;
  9627. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9628. ctx->deferredParams.PushLast(deferred);
  9629. }
  9630. if (funcExpr.property_get == 0)
  9631. Dereference(ctx, true);
  9632. // Add the bytecode for accessing the object on which opCall will be called
  9633. if (ctx->type.dataType.IsObject())
  9634. {
  9635. // Make sure the ProcessPropertyGetAccess knows whether or not to
  9636. // dereference the original object before calling the get accessor
  9637. funcExpr.property_ref = ctx->type.dataType.IsReference();
  9638. }
  9639. MergeExprBytecodeAndType(ctx, &funcExpr);
  9640. ProcessPropertyGetAccessor(ctx, node);
  9641. Dereference(ctx, true);
  9642. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  9643. // Get the opCall methods from the object type
  9644. if (funcExpr.type.dataType.IsObjectHandle())
  9645. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  9646. else
  9647. objIsConst = funcExpr.type.dataType.IsReadOnly();
  9648. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  9649. }
  9650. }
  9651. // Is the symbol matching a class method?
  9652. if (symbolType == SL_CLASSMETHOD)
  9653. {
  9654. // If we're compiling a constructor and the name of the function is super then
  9655. // the constructor of the base class is being called.
  9656. // super cannot be prefixed with a scope operator
  9657. if (scope == "" && m_isConstructor && name == SUPER_TOKEN)
  9658. {
  9659. // If the class is not derived from anyone else, calling super should give an error
  9660. if (outFunc && outFunc->objectType->derivedFrom)
  9661. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  9662. // Must not allow calling base class' constructor multiple times
  9663. if (continueLabels.GetLength() > 0)
  9664. {
  9665. // If a continue label is set we are in a loop
  9666. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  9667. }
  9668. else if (breakLabels.GetLength() > 0)
  9669. {
  9670. // TODO: inheritance: Should eventually allow constructors in switch statements
  9671. // If a break label is set we are either in a loop or a switch statements
  9672. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  9673. }
  9674. else if (m_isConstructorCalled)
  9675. {
  9676. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  9677. }
  9678. m_isConstructorCalled = true;
  9679. // We need to initialize the class members, but only after all the deferred arguments have been completed
  9680. initializeMembers = true;
  9681. }
  9682. else
  9683. {
  9684. // The scope can be used to specify the base class
  9685. builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script);
  9686. }
  9687. // If a class method is being called implicitly, then add the this pointer for the call
  9688. if (funcs.GetLength() && !objectType && outFunc->objectType)
  9689. {
  9690. // Verify that the identified function is actually part of the class hierarchy
  9691. if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
  9692. {
  9693. asCString msg;
  9694. asCString mthd;
  9695. if (scope == "")
  9696. mthd = name;
  9697. else if (scope == "::")
  9698. mthd = scope + name;
  9699. else
  9700. mthd = scope + "::" + name;
  9701. msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf());
  9702. Error(msg, node);
  9703. return -1;
  9704. }
  9705. objectType = outFunc->objectType;
  9706. asCDataType dt = asCDataType::CreateType(objectType, false);
  9707. // The object pointer is located at stack position 0
  9708. ctx->bc.InstrSHORT(asBC_PSF, 0);
  9709. ctx->type.SetVariable(dt, 0, false);
  9710. ctx->type.dataType.MakeReference(true);
  9711. Dereference(ctx, true);
  9712. }
  9713. else if (funcs.GetLength() && !objectType && !outFunc->objectType)
  9714. {
  9715. // Cannot call class methods directly without the object
  9716. asCString msg;
  9717. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  9718. Error(msg, node);
  9719. return -1;
  9720. }
  9721. }
  9722. // Is it a global function?
  9723. if (symbolType == SL_GLOBALFUNC)
  9724. {
  9725. // The symbol lookup identified the namespace to use
  9726. int n = lookupResult.methodName.FindLast("::");
  9727. asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf());
  9728. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  9729. }
  9730. // Is it a type?
  9731. if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE)
  9732. {
  9733. bool isValid = false;
  9734. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, 0, false, &isValid);
  9735. if (isValid)
  9736. return CompileConstructCall(node, ctx);
  9737. }
  9738. // Compile the arguments
  9739. asCArray<asCExprContext *> args;
  9740. asCArray<asSNamedArgument> namedArgs;
  9741. bool isOK = true;
  9742. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9743. {
  9744. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  9745. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  9746. {
  9747. // Evaluate the expression before the function call
  9748. MergeExprBytecode(ctx, args[0]);
  9749. asDELETE(args[0], asCExprContext);
  9750. args.SetLength(0);
  9751. }
  9752. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  9753. if( funcs.GetLength() != 1 )
  9754. {
  9755. // The error was reported by MatchFunctions()
  9756. // Dummy value
  9757. ctx->type.SetDummy();
  9758. isOK = false;
  9759. }
  9760. else
  9761. {
  9762. // Add the default values for arguments not explicitly supplied
  9763. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  9764. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9765. // is it enough to make sure it is in a local variable?
  9766. // For function pointer we must guarantee that the function is safe, i.e.
  9767. // by first storing the function pointer in a local variable (if it isn't already in one)
  9768. if( r == asSUCCESS )
  9769. {
  9770. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  9771. if( func->funcType == asFUNC_FUNCDEF )
  9772. {
  9773. if( objectType && funcExpr.property_get <= 0 )
  9774. {
  9775. // Dereference the object pointer to access the member
  9776. Dereference(ctx, true);
  9777. }
  9778. if( funcExpr.property_get > 0 )
  9779. {
  9780. ProcessPropertyGetAccessor(&funcExpr, node);
  9781. Dereference(&funcExpr, true);
  9782. }
  9783. else
  9784. {
  9785. Dereference(&funcExpr, true);
  9786. ConvertToVariable(&funcExpr);
  9787. }
  9788. // The actual function should be called as if a global function
  9789. objectType = 0;
  9790. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  9791. funcExpr.bc.Instr(asBC_PopPtr);
  9792. asCExprValue tmp = ctx->type;
  9793. MergeExprBytecodeAndType(ctx, &funcExpr);
  9794. ReleaseTemporaryVariable(tmp, &ctx->bc);
  9795. }
  9796. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  9797. }
  9798. else
  9799. isOK = false;
  9800. }
  9801. }
  9802. else
  9803. {
  9804. // Failed to compile the argument list, set the dummy type and continue compilation
  9805. ctx->type.SetDummy();
  9806. isOK = false;
  9807. }
  9808. // Cleanup
  9809. for( asUINT n = 0; n < args.GetLength(); n++ )
  9810. if( args[n] )
  9811. {
  9812. asDELETE(args[n], asCExprContext);
  9813. }
  9814. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9815. if( namedArgs[n].ctx )
  9816. {
  9817. asDELETE(namedArgs[n].ctx, asCExprContext);
  9818. }
  9819. if( initializeMembers )
  9820. {
  9821. asASSERT( m_isConstructor );
  9822. // Need to initialize members here, as they may use the properties of the base class
  9823. // If there are multiple paths that call super(), then there will also be multiple
  9824. // locations with initializations of the members. It is not possible to consolidate
  9825. // these in one place, as the expressions for the initialization are evaluated where
  9826. // they are compiled, which means that they may access different variables depending
  9827. // on the scope where super() is called.
  9828. // Members that don't have an explicit initialization expression will be initialized
  9829. // beginning of the constructor as they are guaranteed not to use at the any
  9830. // members of the base class.
  9831. CompileMemberInitialization(&ctx->bc, false);
  9832. }
  9833. return isOK ? 0 : -1;
  9834. }
  9835. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  9836. {
  9837. asSNameSpace *ns;
  9838. if( scope == "" )
  9839. {
  9840. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  9841. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  9842. ns = outFunc->nameSpace;
  9843. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  9844. ns = outFunc->objectType->nameSpace;
  9845. else
  9846. ns = engine->nameSpaces[0];
  9847. }
  9848. else if( scope == "::" )
  9849. ns = engine->nameSpaces[0];
  9850. else
  9851. ns = engine->FindNameSpace(scope.AddressOf());
  9852. return ns;
  9853. }
  9854. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  9855. {
  9856. int op = node->tokenType;
  9857. // Don't allow any prefix operators except handle on expressions that take address of class method
  9858. if( ctx->IsClassMethod() && op != ttHandle )
  9859. {
  9860. Error(TXT_INVALID_OP_ON_METHOD, node);
  9861. return -1;
  9862. }
  9863. // Don't allow any operators on void expressions
  9864. if( ctx->IsVoidExpression() )
  9865. {
  9866. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9867. return -1;
  9868. }
  9869. IsVariableInitialized(&ctx->type, node);
  9870. if( op == ttHandle )
  9871. {
  9872. if( ctx->methodName != "" )
  9873. {
  9874. // Don't allow taking the handle of a handle
  9875. if( ctx->type.isExplicitHandle )
  9876. {
  9877. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9878. return -1;
  9879. }
  9880. }
  9881. else
  9882. {
  9883. // Don't allow taking handle of a handle, i.e. @@
  9884. if( ctx->type.isExplicitHandle )
  9885. {
  9886. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9887. return -1;
  9888. }
  9889. // @null is allowed even though it is implicit
  9890. if( !ctx->type.IsNullConstant() )
  9891. {
  9892. // Verify that the type allow its handle to be taken
  9893. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  9894. {
  9895. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9896. return -1;
  9897. }
  9898. // Objects that are not local variables are not references
  9899. // Objects allocated on the stack are also not marked as references
  9900. if( !ctx->type.dataType.IsReference() &&
  9901. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  9902. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  9903. {
  9904. Error(TXT_NOT_VALID_REFERENCE, node);
  9905. return -1;
  9906. }
  9907. // Convert the expression to a handle
  9908. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  9909. {
  9910. asCDataType to = ctx->type.dataType;
  9911. to.MakeHandle(true);
  9912. to.MakeReference(true);
  9913. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  9914. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  9915. asASSERT( ctx->type.dataType.IsObjectHandle() );
  9916. }
  9917. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  9918. {
  9919. // For the ASHANDLE type we'll simply set the expression as a handle
  9920. ctx->type.dataType.MakeHandle(true);
  9921. }
  9922. }
  9923. }
  9924. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  9925. ctx->type.isExplicitHandle = true;
  9926. }
  9927. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9928. {
  9929. // Look for the appropriate method
  9930. // There is no overloadable operator for unary plus
  9931. const char *opName = 0;
  9932. switch( op )
  9933. {
  9934. case ttMinus: opName = "opNeg"; break;
  9935. case ttBitNot: opName = "opCom"; break;
  9936. case ttInc: opName = "opPreInc"; break;
  9937. case ttDec: opName = "opPreDec"; break;
  9938. }
  9939. if( opName )
  9940. {
  9941. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9942. ProcessPropertyGetAccessor(ctx, node);
  9943. // 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
  9944. // Find the correct method
  9945. bool isConst = ctx->type.dataType.IsObjectConst();
  9946. asCArray<int> funcs;
  9947. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  9948. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9949. {
  9950. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9951. if( func->name == opName &&
  9952. func->parameterTypes.GetLength() == 0 &&
  9953. (!isConst || func->IsReadOnly()) )
  9954. {
  9955. funcs.PushLast(func->id);
  9956. }
  9957. }
  9958. // Did we find the method?
  9959. if( funcs.GetLength() == 1 )
  9960. {
  9961. asCArray<asCExprContext *> args;
  9962. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  9963. return 0;
  9964. }
  9965. else if( funcs.GetLength() == 0 )
  9966. {
  9967. asCString str;
  9968. str = asCString(opName) + "()";
  9969. if( isConst )
  9970. str += " const";
  9971. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9972. Error(str, node);
  9973. ctx->type.SetDummy();
  9974. return -1;
  9975. }
  9976. else if( funcs.GetLength() > 1 )
  9977. {
  9978. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9979. PrintMatchingFuncs(funcs, node);
  9980. ctx->type.SetDummy();
  9981. return -1;
  9982. }
  9983. }
  9984. else if( op == ttPlus )
  9985. {
  9986. Error(TXT_ILLEGAL_OPERATION, node);
  9987. ctx->type.SetDummy();
  9988. return -1;
  9989. }
  9990. }
  9991. else if( op == ttPlus || op == ttMinus )
  9992. {
  9993. // This is only for primitives. Objects are treated in the above block
  9994. // Make sure the type is a math type
  9995. if( !(ctx->type.dataType.IsIntegerType() ||
  9996. ctx->type.dataType.IsUnsignedType() ||
  9997. ctx->type.dataType.IsFloatType() ||
  9998. ctx->type.dataType.IsDoubleType() ) )
  9999. {
  10000. Error(TXT_ILLEGAL_OPERATION, node);
  10001. return -1;
  10002. }
  10003. ProcessPropertyGetAccessor(ctx, node);
  10004. asCDataType to = ctx->type.dataType;
  10005. if( ctx->type.dataType.IsUnsignedType() )
  10006. {
  10007. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10008. to = asCDataType::CreatePrimitive(ttInt8, false);
  10009. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10010. to = asCDataType::CreatePrimitive(ttInt16, false);
  10011. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10012. to = asCDataType::CreatePrimitive(ttInt, false);
  10013. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10014. to = asCDataType::CreatePrimitive(ttInt64, false);
  10015. else
  10016. {
  10017. Error(TXT_INVALID_TYPE, node);
  10018. return -1;
  10019. }
  10020. }
  10021. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10022. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  10023. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  10024. if( !ctx->type.isConstant )
  10025. {
  10026. ConvertToTempVariable(ctx);
  10027. asASSERT(!ctx->type.isLValue);
  10028. if( op == ttMinus )
  10029. {
  10030. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10031. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  10032. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10033. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  10034. else if( ctx->type.dataType.IsFloatType() )
  10035. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  10036. else if( ctx->type.dataType.IsDoubleType() )
  10037. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  10038. else
  10039. {
  10040. Error(TXT_ILLEGAL_OPERATION, node);
  10041. return -1;
  10042. }
  10043. return 0;
  10044. }
  10045. }
  10046. else
  10047. {
  10048. if( op == ttMinus )
  10049. {
  10050. if (ctx->type.dataType.IsIntegerType())
  10051. {
  10052. if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10053. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  10054. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10055. ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
  10056. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
  10057. ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
  10058. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
  10059. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  10060. }
  10061. else if( ctx->type.dataType.IsFloatType() )
  10062. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  10063. else if( ctx->type.dataType.IsDoubleType() )
  10064. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  10065. else
  10066. {
  10067. Error(TXT_ILLEGAL_OPERATION, node);
  10068. return -1;
  10069. }
  10070. return 0;
  10071. }
  10072. }
  10073. }
  10074. else if( op == ttNot )
  10075. {
  10076. // Allow value types to be converted to bool using 'bool opImplConv()'
  10077. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  10078. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  10079. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  10080. {
  10081. if( ctx->type.isConstant )
  10082. {
  10083. #if AS_SIZEOF_BOOL == 1
  10084. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10085. #else
  10086. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10087. #endif
  10088. return 0;
  10089. }
  10090. ProcessPropertyGetAccessor(ctx, node);
  10091. ConvertToTempVariable(ctx);
  10092. asASSERT(!ctx->type.isLValue);
  10093. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10094. }
  10095. else
  10096. {
  10097. Error(TXT_ILLEGAL_OPERATION, node);
  10098. return -1;
  10099. }
  10100. }
  10101. else if( op == ttBitNot )
  10102. {
  10103. ProcessPropertyGetAccessor(ctx, node);
  10104. asCDataType to = ctx->type.dataType;
  10105. if( ctx->type.dataType.IsIntegerType() )
  10106. {
  10107. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10108. to = asCDataType::CreatePrimitive(ttUInt8, false);
  10109. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10110. to = asCDataType::CreatePrimitive(ttUInt16, false);
  10111. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10112. to = asCDataType::CreatePrimitive(ttUInt, false);
  10113. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10114. to = asCDataType::CreatePrimitive(ttUInt64, false);
  10115. else
  10116. {
  10117. Error(TXT_INVALID_TYPE, node);
  10118. return -1;
  10119. }
  10120. }
  10121. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10122. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  10123. if( ctx->type.dataType.IsUnsignedType() )
  10124. {
  10125. if( ctx->type.isConstant )
  10126. {
  10127. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10128. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  10129. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10130. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  10131. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10132. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  10133. else
  10134. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  10135. return 0;
  10136. }
  10137. ConvertToTempVariable(ctx);
  10138. asASSERT(!ctx->type.isLValue);
  10139. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10140. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  10141. else
  10142. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  10143. }
  10144. else
  10145. {
  10146. Error(TXT_ILLEGAL_OPERATION, node);
  10147. return -1;
  10148. }
  10149. }
  10150. else if( op == ttInc || op == ttDec )
  10151. {
  10152. // Need a reference to the primitive that will be updated
  10153. // The result of this expression is the same reference as before
  10154. // Make sure the reference isn't a temporary variable
  10155. if( ctx->type.isTemporary )
  10156. {
  10157. Error(TXT_REF_IS_TEMP, node);
  10158. return -1;
  10159. }
  10160. if( ctx->type.dataType.IsReadOnly() )
  10161. {
  10162. Error(TXT_REF_IS_READ_ONLY, node);
  10163. return -1;
  10164. }
  10165. if( ctx->property_get || ctx->property_set )
  10166. {
  10167. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10168. return -1;
  10169. }
  10170. if( !ctx->type.isLValue )
  10171. {
  10172. Error(TXT_NOT_LVALUE, node);
  10173. return -1;
  10174. }
  10175. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10176. ConvertToReference(ctx);
  10177. else if( !ctx->type.dataType.IsReference() )
  10178. {
  10179. Error(TXT_NOT_VALID_REFERENCE, node);
  10180. return -1;
  10181. }
  10182. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10183. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10184. {
  10185. if( op == ttInc )
  10186. ctx->bc.Instr(asBC_INCi64);
  10187. else
  10188. ctx->bc.Instr(asBC_DECi64);
  10189. }
  10190. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  10191. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  10192. {
  10193. if( op == ttInc )
  10194. ctx->bc.Instr(asBC_INCi);
  10195. else
  10196. ctx->bc.Instr(asBC_DECi);
  10197. }
  10198. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10199. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10200. {
  10201. if( op == ttInc )
  10202. ctx->bc.Instr(asBC_INCi16);
  10203. else
  10204. ctx->bc.Instr(asBC_DECi16);
  10205. }
  10206. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10207. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10208. {
  10209. if( op == ttInc )
  10210. ctx->bc.Instr(asBC_INCi8);
  10211. else
  10212. ctx->bc.Instr(asBC_DECi8);
  10213. }
  10214. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  10215. {
  10216. if( op == ttInc )
  10217. ctx->bc.Instr(asBC_INCf);
  10218. else
  10219. ctx->bc.Instr(asBC_DECf);
  10220. }
  10221. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  10222. {
  10223. if( op == ttInc )
  10224. ctx->bc.Instr(asBC_INCd);
  10225. else
  10226. ctx->bc.Instr(asBC_DECd);
  10227. }
  10228. else
  10229. {
  10230. Error(TXT_ILLEGAL_OPERATION, node);
  10231. return -1;
  10232. }
  10233. }
  10234. else
  10235. {
  10236. // Unknown operator
  10237. asASSERT(false);
  10238. return -1;
  10239. }
  10240. return 0;
  10241. }
  10242. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  10243. {
  10244. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10245. {
  10246. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  10247. ctx->type.dataType.MakeReference(true);
  10248. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  10249. }
  10250. }
  10251. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10252. {
  10253. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  10254. }
  10255. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10256. {
  10257. if( engine->ep.propertyAccessorMode == 0 )
  10258. {
  10259. // Property accessors have been disabled by the application
  10260. return 0;
  10261. }
  10262. int getId = 0, setId = 0;
  10263. asCString getName = "get_" + name;
  10264. asCString setName = "set_" + name;
  10265. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  10266. if( ctx->type.dataType.IsObject() )
  10267. {
  10268. asASSERT( ns == 0 );
  10269. // Don't look for property accessors in script classes if the script
  10270. // property accessors have been disabled by the application
  10271. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  10272. engine->ep.propertyAccessorMode == 2 )
  10273. {
  10274. // Check if the object has any methods with the corresponding accessor name(s)
  10275. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10276. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10277. {
  10278. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  10279. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10280. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10281. {
  10282. if( getId == 0 )
  10283. getId = ot->methods[n];
  10284. else
  10285. {
  10286. if( multipleGetFuncs.GetLength() == 0 )
  10287. multipleGetFuncs.PushLast(getId);
  10288. multipleGetFuncs.PushLast(ot->methods[n]);
  10289. }
  10290. }
  10291. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10292. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10293. {
  10294. if( setId == 0 )
  10295. setId = ot->methods[n];
  10296. else
  10297. {
  10298. if( multipleSetFuncs.GetLength() == 0 )
  10299. multipleSetFuncs.PushLast(setId);
  10300. multipleSetFuncs.PushLast(ot->methods[n]);
  10301. }
  10302. }
  10303. }
  10304. }
  10305. }
  10306. else
  10307. {
  10308. asASSERT( ns != 0 );
  10309. // Look for appropriate global functions.
  10310. asCArray<int> funcs;
  10311. asUINT n;
  10312. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  10313. for( n = 0; n < funcs.GetLength(); n++ )
  10314. {
  10315. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10316. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10317. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10318. {
  10319. if( getId == 0 )
  10320. getId = funcs[n];
  10321. else
  10322. {
  10323. if( multipleGetFuncs.GetLength() == 0 )
  10324. multipleGetFuncs.PushLast(getId);
  10325. multipleGetFuncs.PushLast(funcs[n]);
  10326. }
  10327. }
  10328. }
  10329. funcs.SetLength(0);
  10330. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  10331. for( n = 0; n < funcs.GetLength(); n++ )
  10332. {
  10333. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10334. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10335. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10336. {
  10337. if( setId == 0 )
  10338. setId = funcs[n];
  10339. else
  10340. {
  10341. if( multipleSetFuncs.GetLength() == 0 )
  10342. multipleSetFuncs.PushLast(setId);
  10343. multipleSetFuncs.PushLast(funcs[n]);
  10344. }
  10345. }
  10346. }
  10347. }
  10348. bool isConst = ctx->type.dataType.IsObjectConst();
  10349. // Check for multiple matches
  10350. if( multipleGetFuncs.GetLength() > 0 )
  10351. {
  10352. // Filter the list by constness
  10353. FilterConst(multipleGetFuncs, !isConst);
  10354. if( multipleGetFuncs.GetLength() > 1 )
  10355. {
  10356. if (node)
  10357. {
  10358. asCString str;
  10359. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  10360. Error(str, node);
  10361. PrintMatchingFuncs(multipleGetFuncs, node);
  10362. }
  10363. return -1;
  10364. }
  10365. else
  10366. {
  10367. // The id may have changed
  10368. getId = multipleGetFuncs[0];
  10369. }
  10370. }
  10371. if( multipleSetFuncs.GetLength() > 0 )
  10372. {
  10373. // Filter the list by constness
  10374. FilterConst(multipleSetFuncs, !isConst);
  10375. if( multipleSetFuncs.GetLength() > 1 )
  10376. {
  10377. if (node)
  10378. {
  10379. asCString str;
  10380. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  10381. Error(str, node);
  10382. PrintMatchingFuncs(multipleSetFuncs, node);
  10383. }
  10384. return -1;
  10385. }
  10386. else
  10387. {
  10388. // The id may have changed
  10389. setId = multipleSetFuncs[0];
  10390. }
  10391. }
  10392. // Check for type compatibility between get and set accessor
  10393. if( getId && setId )
  10394. {
  10395. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  10396. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  10397. // It is permitted for a getter to return a handle and the setter to take a reference
  10398. int idx = (arg?1:0);
  10399. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  10400. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  10401. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  10402. {
  10403. if (node)
  10404. {
  10405. asCString str;
  10406. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  10407. Error(str, node);
  10408. asCArray<int> funcs;
  10409. funcs.PushLast(getId);
  10410. funcs.PushLast(setId);
  10411. PrintMatchingFuncs(funcs, node);
  10412. }
  10413. return -1;
  10414. }
  10415. }
  10416. // Check if we are within one of the accessors
  10417. int realGetId = getId;
  10418. int realSetId = setId;
  10419. if( outFunc->objectType && isThisAccess )
  10420. {
  10421. // The property accessors would be virtual functions, so we need to find the real implementation
  10422. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  10423. if( getFunc &&
  10424. getFunc->funcType == asFUNC_VIRTUAL &&
  10425. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  10426. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  10427. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  10428. if( setFunc &&
  10429. setFunc->funcType == asFUNC_VIRTUAL &&
  10430. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  10431. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  10432. }
  10433. // Avoid recursive call, by not treating this as a property accessor call.
  10434. // This will also allow having the real property with the same name as the accessors.
  10435. if( (isThisAccess || outFunc->objectType == 0) &&
  10436. ((realGetId && realGetId == outFunc->id) ||
  10437. (realSetId && realSetId == outFunc->id)) )
  10438. {
  10439. getId = 0;
  10440. setId = 0;
  10441. }
  10442. // Check if the application has disabled script written property accessors
  10443. if( engine->ep.propertyAccessorMode == 1 )
  10444. {
  10445. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  10446. getId = 0;
  10447. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  10448. setId = 0;
  10449. }
  10450. if( getId || setId )
  10451. {
  10452. // Property accessors were found, but we don't know which is to be used yet, so
  10453. // we just prepare the bytecode for the method call, and then store the function ids
  10454. // so that the right one can be used when we get there.
  10455. ctx->property_get = getId;
  10456. ctx->property_set = setId;
  10457. bool isRefSafe = ctx->type.isRefSafe;
  10458. if( ctx->type.dataType.IsObject() )
  10459. {
  10460. // If the object is read-only then we need to remember that
  10461. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  10462. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  10463. ctx->property_const = true;
  10464. else
  10465. ctx->property_const = false;
  10466. // If the object is a handle then we need to remember that
  10467. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  10468. ctx->property_ref = ctx->type.dataType.IsReference();
  10469. }
  10470. // The setter's parameter type is used as the property type,
  10471. // unless only the getter is available
  10472. asCDataType dt;
  10473. if( setId )
  10474. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  10475. else
  10476. dt = builder->GetFunctionDescription(getId)->returnType;
  10477. // Just change the type, the context must still maintain information
  10478. // about previous variable offset and the indicator of temporary variable.
  10479. int offset = ctx->type.stackOffset;
  10480. bool isTemp = ctx->type.isTemporary;
  10481. ctx->type.Set(dt);
  10482. ctx->type.stackOffset = (short)offset;
  10483. ctx->type.isTemporary = isTemp;
  10484. ctx->exprNode = node;
  10485. // Remember if the object is safe, so the invocation of the property
  10486. // accessor doesn't needlessly make a safe copy of the handle
  10487. ctx->type.isRefSafe = isRefSafe;
  10488. // Store the argument for later use
  10489. if( arg )
  10490. {
  10491. ctx->property_arg = asNEW(asCExprContext)(engine);
  10492. if( ctx->property_arg == 0 )
  10493. {
  10494. // Out of memory
  10495. return -1;
  10496. }
  10497. MergeExprBytecodeAndType(ctx->property_arg, arg);
  10498. }
  10499. return 1;
  10500. }
  10501. // No accessor was found
  10502. return 0;
  10503. }
  10504. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  10505. {
  10506. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  10507. if( !ctx->property_set )
  10508. {
  10509. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  10510. return -1;
  10511. }
  10512. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  10513. // Make sure the arg match the property
  10514. asCArray<int> funcs;
  10515. funcs.PushLast(ctx->property_set);
  10516. asCArray<asCExprContext *> args;
  10517. if( ctx->property_arg )
  10518. args.PushLast(ctx->property_arg);
  10519. args.PushLast(arg);
  10520. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10521. if( funcs.GetLength() == 0 )
  10522. {
  10523. // MatchFunctions already reported the error
  10524. if( ctx->property_arg )
  10525. {
  10526. asDELETE(ctx->property_arg, asCExprContext);
  10527. ctx->property_arg = 0;
  10528. }
  10529. return -1;
  10530. }
  10531. if( func->objectType )
  10532. {
  10533. // Setup the context with the original type so the method call gets built correctly
  10534. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10535. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10536. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10537. // Don't allow the call if the object is read-only and the property accessor is not const
  10538. if( ctx->property_const && !func->IsReadOnly() )
  10539. {
  10540. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10541. asCArray<int> funcCandidates;
  10542. funcCandidates.PushLast(ctx->property_set);
  10543. PrintMatchingFuncs(funcCandidates, node);
  10544. }
  10545. }
  10546. // Call the accessor
  10547. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  10548. ctx->property_get = 0;
  10549. ctx->property_set = 0;
  10550. if( ctx->property_arg )
  10551. {
  10552. asDELETE(ctx->property_arg, asCExprContext);
  10553. ctx->property_arg = 0;
  10554. }
  10555. return 0;
  10556. }
  10557. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  10558. {
  10559. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  10560. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  10561. // to support value types, since it would be a single call
  10562. // Compound assignment for indexed property accessors is not supported yet
  10563. if( lctx->property_arg != 0 )
  10564. {
  10565. // Process the property to free the memory
  10566. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10567. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  10568. return -1;
  10569. }
  10570. // Compound assignments require both get and set accessors
  10571. if( lctx->property_set == 0 || lctx->property_get == 0 )
  10572. {
  10573. // Process the property to free the memory
  10574. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10575. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  10576. return -1;
  10577. }
  10578. // Property accessors on value types (or scoped references types) are not supported since
  10579. // it is not possible to guarantee that the object will stay alive between the two calls
  10580. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  10581. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  10582. {
  10583. // Process the property to free the memory
  10584. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10585. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  10586. return -1;
  10587. }
  10588. // Translate the compound assignment to the corresponding dual operator
  10589. switch( op )
  10590. {
  10591. case ttAddAssign: op = ttPlus; break;
  10592. case ttSubAssign: op = ttMinus; break;
  10593. case ttMulAssign: op = ttStar; break;
  10594. case ttDivAssign: op = ttSlash; break;
  10595. case ttModAssign: op = ttPercent; break;
  10596. case ttPowAssign: op = ttStarStar; break;
  10597. case ttAndAssign: op = ttAmp; break;
  10598. case ttOrAssign: op = ttBitOr; break;
  10599. case ttXorAssign: op = ttBitXor; break;
  10600. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  10601. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  10602. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  10603. default: op = ttUnrecognizedToken; break;
  10604. }
  10605. if( op == ttUnrecognizedToken )
  10606. {
  10607. // Shouldn't happen
  10608. asASSERT(false);
  10609. // Process the property to free the memory
  10610. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10611. return -1;
  10612. }
  10613. asCExprContext before(engine);
  10614. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  10615. {
  10616. // Keep a reference to the object in a local variable
  10617. before.bc.AddCode(&lctx->bc);
  10618. asUINT len = reservedVariables.GetLength();
  10619. rctx->bc.GetVarsUsed(reservedVariables);
  10620. before.bc.GetVarsUsed(reservedVariables);
  10621. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  10622. int offset = AllocateVariable(dt, true);
  10623. reservedVariables.SetLength(len);
  10624. before.type.SetVariable(dt, offset, true);
  10625. if( lctx->property_ref )
  10626. before.bc.Instr(asBC_RDSPtr);
  10627. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  10628. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  10629. before.bc.Instr(asBC_PopPtr);
  10630. if( lctx->type.isTemporary )
  10631. {
  10632. // Add the release of the temporary variable as a deferred expression
  10633. asSDeferredParam deferred;
  10634. deferred.origExpr = 0;
  10635. deferred.argInOutFlags = asTM_INREF;
  10636. deferred.argNode = 0;
  10637. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  10638. before.deferredParams.PushLast(deferred);
  10639. }
  10640. // Update the left expression to use the local variable
  10641. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10642. lctx->type.stackOffset = (short)offset;
  10643. lctx->property_ref = true;
  10644. // Don't release the temporary variable too early
  10645. lctx->type.isTemporary = false;
  10646. ctx->bc.AddCode(&before.bc);
  10647. }
  10648. // Keep the original information on the property
  10649. asCExprContext llctx(engine);
  10650. llctx.type = lctx->type;
  10651. llctx.property_arg = lctx->property_arg;
  10652. llctx.property_const = lctx->property_const;
  10653. llctx.property_get = lctx->property_get;
  10654. llctx.property_handle = lctx->property_handle;
  10655. llctx.property_ref = lctx->property_ref;
  10656. llctx.property_set = lctx->property_set;
  10657. // Compile the dual operator using the get accessor
  10658. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  10659. // If we made a local variable to hold the reference it must be reused
  10660. if( before.type.stackOffset )
  10661. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  10662. // Compile the assignment using the set accessor
  10663. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  10664. MergeExprBytecodeAndType(ctx, &llctx);
  10665. if( before.type.stackOffset )
  10666. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  10667. asASSERT( ctx->deferredParams.GetLength() == 0 );
  10668. ctx->deferredParams = before.deferredParams;
  10669. ProcessDeferredParams(ctx);
  10670. return 0;
  10671. }
  10672. void asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  10673. {
  10674. // If no property accessor has been prepared then don't do anything
  10675. if( !ctx->property_get && !ctx->property_set )
  10676. return;
  10677. if( !ctx->property_get )
  10678. {
  10679. // Raise error on missing accessor
  10680. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  10681. ctx->type.SetDummy();
  10682. return;
  10683. }
  10684. asCExprValue objType = ctx->type;
  10685. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  10686. // Make sure the arg match the property
  10687. asCArray<int> funcs;
  10688. funcs.PushLast(ctx->property_get);
  10689. asCArray<asCExprContext *> args;
  10690. if( ctx->property_arg )
  10691. args.PushLast(ctx->property_arg);
  10692. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10693. if( funcs.GetLength() == 0 )
  10694. {
  10695. // MatchFunctions already reported the error
  10696. if( ctx->property_arg )
  10697. {
  10698. asDELETE(ctx->property_arg, asCExprContext);
  10699. ctx->property_arg = 0;
  10700. }
  10701. ctx->type.SetDummy();
  10702. return;
  10703. }
  10704. if( func->objectType )
  10705. {
  10706. // Setup the context with the original type so the method call gets built correctly
  10707. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10708. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10709. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10710. // Don't allow the call if the object is read-only and the property accessor is not const
  10711. if( ctx->property_const && !func->IsReadOnly() )
  10712. {
  10713. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10714. asCArray<int> funcCandidates;
  10715. funcCandidates.PushLast(ctx->property_get);
  10716. PrintMatchingFuncs(funcCandidates, node);
  10717. }
  10718. }
  10719. // The explicit handle flag must be remembered
  10720. bool isExplicitHandle = ctx->type.isExplicitHandle;
  10721. // Call the accessor
  10722. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  10723. if( isExplicitHandle )
  10724. ctx->type.isExplicitHandle = true;
  10725. // Clear the property get/set ids
  10726. ctx->property_get = 0;
  10727. ctx->property_set = 0;
  10728. if( ctx->property_arg )
  10729. {
  10730. asDELETE(ctx->property_arg, asCExprContext);
  10731. ctx->property_arg = 0;
  10732. }
  10733. }
  10734. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  10735. {
  10736. // Don't allow any postfix operators on expressions that take address of class method
  10737. if( ctx->IsClassMethod() )
  10738. {
  10739. Error(TXT_INVALID_OP_ON_METHOD, node);
  10740. return -1;
  10741. }
  10742. // Don't allow any operators on void expressions
  10743. if( ctx->IsVoidExpression() )
  10744. {
  10745. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10746. return -1;
  10747. }
  10748. // Check if the variable is initialized (if it indeed is a variable)
  10749. IsVariableInitialized(&ctx->type, node);
  10750. int op = node->tokenType;
  10751. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10752. {
  10753. const char *opName = 0;
  10754. switch( op )
  10755. {
  10756. case ttInc: opName = "opPostInc"; break;
  10757. case ttDec: opName = "opPostDec"; break;
  10758. }
  10759. if( opName )
  10760. {
  10761. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10762. ProcessPropertyGetAccessor(ctx, node);
  10763. // 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
  10764. // Find the correct method
  10765. bool isConst = ctx->type.dataType.IsObjectConst();
  10766. asCArray<int> funcs;
  10767. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10768. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10769. {
  10770. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10771. if( func->name == opName &&
  10772. func->parameterTypes.GetLength() == 0 &&
  10773. (!isConst || func->IsReadOnly()) )
  10774. {
  10775. funcs.PushLast(func->id);
  10776. }
  10777. }
  10778. // Did we find the method?
  10779. if( funcs.GetLength() == 1 )
  10780. {
  10781. asCArray<asCExprContext *> args;
  10782. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10783. return 0;
  10784. }
  10785. else if( funcs.GetLength() == 0 )
  10786. {
  10787. asCString str;
  10788. str = asCString(opName) + "()";
  10789. if( isConst )
  10790. str += " const";
  10791. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10792. Error(str, node);
  10793. ctx->type.SetDummy();
  10794. return -1;
  10795. }
  10796. else if( funcs.GetLength() > 1 )
  10797. {
  10798. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10799. PrintMatchingFuncs(funcs, node);
  10800. ctx->type.SetDummy();
  10801. return -1;
  10802. }
  10803. }
  10804. }
  10805. else if( op == ttInc || op == ttDec )
  10806. {
  10807. // Make sure the reference isn't a temporary variable
  10808. if( ctx->type.isTemporary )
  10809. {
  10810. Error(TXT_REF_IS_TEMP, node);
  10811. return -1;
  10812. }
  10813. if( ctx->type.dataType.IsReadOnly() )
  10814. {
  10815. Error(TXT_REF_IS_READ_ONLY, node);
  10816. return -1;
  10817. }
  10818. if( ctx->property_get || ctx->property_set )
  10819. {
  10820. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10821. return -1;
  10822. }
  10823. if( !ctx->type.isLValue )
  10824. {
  10825. Error(TXT_NOT_LVALUE, node);
  10826. return -1;
  10827. }
  10828. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10829. ConvertToReference(ctx);
  10830. else if( !ctx->type.dataType.IsReference() )
  10831. {
  10832. Error(TXT_NOT_VALID_REFERENCE, node);
  10833. return -1;
  10834. }
  10835. // Copy the value to a temp before changing it
  10836. ConvertToTempVariable(ctx);
  10837. asASSERT(!ctx->type.isLValue);
  10838. // Increment the value pointed to by the reference still in the register
  10839. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  10840. if( ctx->type.dataType.IsDoubleType() )
  10841. {
  10842. iInc = asBC_INCd;
  10843. iDec = asBC_DECd;
  10844. }
  10845. else if( ctx->type.dataType.IsFloatType() )
  10846. {
  10847. iInc = asBC_INCf;
  10848. iDec = asBC_DECf;
  10849. }
  10850. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  10851. {
  10852. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10853. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10854. {
  10855. iInc = asBC_INCi16;
  10856. iDec = asBC_DECi16;
  10857. }
  10858. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10859. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10860. {
  10861. iInc = asBC_INCi8;
  10862. iDec = asBC_DECi8;
  10863. }
  10864. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10865. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10866. {
  10867. iInc = asBC_INCi64;
  10868. iDec = asBC_DECi64;
  10869. }
  10870. }
  10871. else
  10872. {
  10873. Error(TXT_ILLEGAL_OPERATION, node);
  10874. return -1;
  10875. }
  10876. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  10877. }
  10878. else if( op == ttDot )
  10879. {
  10880. if( node->firstChild->nodeType == snIdentifier )
  10881. {
  10882. ProcessPropertyGetAccessor(ctx, node);
  10883. // Get the property name
  10884. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  10885. if( ctx->type.dataType.IsObject() )
  10886. {
  10887. // We need to look for get/set property accessors.
  10888. // If found, the context stores information on the get/set accessors
  10889. // until it is known which is to be used.
  10890. int r = 0;
  10891. if( node->next && node->next->tokenType == ttOpenBracket )
  10892. {
  10893. // The property accessor should take an index arg
  10894. asCExprContext dummyArg(engine);
  10895. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  10896. }
  10897. if( r == 0 )
  10898. r = FindPropertyAccessor(name, ctx, node, 0);
  10899. if( r != 0 )
  10900. return r;
  10901. if( !ctx->type.dataType.IsPrimitive() )
  10902. Dereference(ctx, true);
  10903. if( ctx->type.dataType.IsObjectHandle() )
  10904. {
  10905. // Convert the handle to a normal object
  10906. asCDataType dt = ctx->type.dataType;
  10907. dt.MakeHandle(false);
  10908. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  10909. // The handle may not have been an lvalue, but the dereferenced object is
  10910. ctx->type.isLValue = true;
  10911. }
  10912. bool isConst = ctx->type.dataType.IsObjectConst();
  10913. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  10914. if( prop )
  10915. {
  10916. // Is the property access allowed?
  10917. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  10918. {
  10919. asCString msg;
  10920. if( prop->isPrivate )
  10921. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  10922. else
  10923. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  10924. Error(msg, node);
  10925. }
  10926. // Adjust the pointer for composite member
  10927. // 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
  10928. if( prop->compositeOffset || prop->isCompositeIndirect )
  10929. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  10930. if (prop->isCompositeIndirect)
  10931. ctx->bc.Instr(asBC_RDSPtr);
  10932. // Put the offset on the stack
  10933. // This must always be done even if the offset is 0 so the type info is stored
  10934. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  10935. if( prop->type.IsReference() )
  10936. ctx->bc.Instr(asBC_RDSPtr);
  10937. // Reference to primitive must be stored in the temp register
  10938. if( prop->type.IsPrimitive() )
  10939. {
  10940. ctx->bc.Instr(asBC_PopRPtr);
  10941. }
  10942. // Keep information about temporary variables as deferred expression
  10943. if( ctx->type.isTemporary )
  10944. {
  10945. // Add the release of this reference, as a deferred expression
  10946. asSDeferredParam deferred;
  10947. deferred.origExpr = 0;
  10948. deferred.argInOutFlags = asTM_INREF;
  10949. deferred.argNode = 0;
  10950. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  10951. ctx->deferredParams.PushLast(deferred);
  10952. }
  10953. // Set the new type and make sure it is not treated as a variable anymore
  10954. ctx->type.dataType = prop->type;
  10955. ctx->type.dataType.MakeReference(true);
  10956. ctx->type.isVariable = false;
  10957. ctx->type.isTemporary = false;
  10958. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  10959. {
  10960. // Objects that are members are not references
  10961. ctx->type.dataType.MakeReference(false);
  10962. // The object is safe (life time guaranteed) if the parent object is also safe
  10963. }
  10964. else if (ctx->type.dataType.IsObjectHandle())
  10965. {
  10966. // A object accessed through a handle cannot be considered safe,
  10967. // as it can be cleared at any time
  10968. ctx->type.isRefSafe = false;
  10969. }
  10970. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  10971. }
  10972. else
  10973. {
  10974. // If the name is not a property, the compiler must check if the name matches
  10975. // a method, which can be used for constructing delegates
  10976. asIScriptFunction *func = 0;
  10977. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10978. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10979. {
  10980. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  10981. {
  10982. func = engine->scriptFunctions[ot->methods[n]];
  10983. break;
  10984. }
  10985. }
  10986. if( func )
  10987. {
  10988. // An object method was found. Keep the name of the method in the expression, but
  10989. // don't actually modify the bytecode at this point since it is not yet known what
  10990. // the method will be used for, or even what overloaded method should be used.
  10991. ctx->methodName = name;
  10992. }
  10993. else
  10994. {
  10995. asCString str;
  10996. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10997. Error(str, node);
  10998. return -1;
  10999. }
  11000. }
  11001. }
  11002. else
  11003. {
  11004. asCString str;
  11005. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11006. Error(str, node);
  11007. return -1;
  11008. }
  11009. }
  11010. else
  11011. {
  11012. // Make sure it is an object we are accessing
  11013. if( !ctx->type.dataType.IsObject() )
  11014. {
  11015. asCString str;
  11016. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11017. Error(str, node);
  11018. return -1;
  11019. }
  11020. // Process the get property accessor
  11021. ProcessPropertyGetAccessor(ctx, node);
  11022. // Compile function call
  11023. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  11024. if( r < 0 ) return r;
  11025. }
  11026. }
  11027. else if( op == ttOpenBracket )
  11028. {
  11029. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  11030. // then we should use that instead of processing it now. If the argument has already been
  11031. // evaluated, then we should process the property accessor as a get access now as the new
  11032. // index operator is on the result of that accessor.
  11033. asCString propertyName;
  11034. asSNameSpace *ns = 0;
  11035. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  11036. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  11037. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  11038. {
  11039. // Determine the name of the property accessor
  11040. asCScriptFunction *func = 0;
  11041. if( ctx->property_get )
  11042. func = builder->GetFunctionDescription(ctx->property_get);
  11043. else
  11044. func = builder->GetFunctionDescription(ctx->property_set);
  11045. propertyName = func->GetName();
  11046. propertyName = propertyName.SubString(4);
  11047. // Set the original type of the expression so we can re-evaluate the property accessor
  11048. if( func->objectType )
  11049. {
  11050. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  11051. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  11052. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  11053. }
  11054. else
  11055. {
  11056. // Store the namespace where the function is declared
  11057. // so the same function can be found later
  11058. ctx->type.SetDummy();
  11059. ns = func->nameSpace;
  11060. }
  11061. ctx->property_get = ctx->property_set = 0;
  11062. if( ctx->property_arg )
  11063. {
  11064. asDELETE(ctx->property_arg, asCExprContext);
  11065. ctx->property_arg = 0;
  11066. }
  11067. }
  11068. else
  11069. {
  11070. if( !ctx->type.dataType.IsObject() )
  11071. {
  11072. asCString str;
  11073. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11074. Error(str, node);
  11075. return -1;
  11076. }
  11077. ProcessPropertyGetAccessor(ctx, node);
  11078. }
  11079. // Compile the expression
  11080. bool isOK = true;
  11081. asCArray<asCExprContext *> args;
  11082. asCArray<asSNamedArgument> namedArgs;
  11083. asASSERT( node->firstChild->nodeType == snArgList );
  11084. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  11085. {
  11086. // Check for the existence of the opIndex method
  11087. bool lookForProperty = true;
  11088. if( propertyName == "" )
  11089. {
  11090. bool isConst = ctx->type.dataType.IsObjectConst();
  11091. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11092. asCArray<int> funcs;
  11093. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  11094. if( funcs.GetLength() > 0 )
  11095. {
  11096. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  11097. lookForProperty = false;
  11098. // Determine which of opIndex methods that match
  11099. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  11100. if( funcs.GetLength() != 1 )
  11101. {
  11102. // The error has already been reported by MatchFunctions
  11103. isOK = false;
  11104. }
  11105. else
  11106. {
  11107. // Add the default values for arguments not explicitly supplied
  11108. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  11109. if( r == 0 )
  11110. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset);
  11111. else
  11112. isOK = false;
  11113. }
  11114. }
  11115. }
  11116. if( lookForProperty && isOK )
  11117. {
  11118. if( args.GetLength() != 1 )
  11119. {
  11120. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  11121. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  11122. isOK = false;
  11123. }
  11124. else
  11125. {
  11126. Dereference(ctx, true);
  11127. asCExprContext lctx(engine);
  11128. MergeExprBytecodeAndType(&lctx, ctx);
  11129. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  11130. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  11131. if (r == 0)
  11132. {
  11133. asCString str;
  11134. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11135. Error(str, node);
  11136. isOK = false;
  11137. }
  11138. else if (r < 0)
  11139. isOK = false;
  11140. if (isOK)
  11141. MergeExprBytecodeAndType(ctx, &lctx);
  11142. }
  11143. }
  11144. }
  11145. else
  11146. isOK = false;
  11147. // Cleanup
  11148. for( asUINT n = 0; n < args.GetLength(); n++ )
  11149. if( args[n] )
  11150. {
  11151. asDELETE(args[n], asCExprContext);
  11152. }
  11153. if( !isOK )
  11154. return -1;
  11155. }
  11156. else if( op == ttOpenParanthesis )
  11157. {
  11158. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  11159. // Make sure the expression is a funcdef or an object that may have opCall methods
  11160. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  11161. {
  11162. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  11163. return -1;
  11164. }
  11165. // Compile arguments
  11166. asCArray<asCExprContext *> args;
  11167. asCArray<asSNamedArgument> namedArgs;
  11168. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  11169. {
  11170. // Match arguments with the funcdef
  11171. asCArray<int> funcs;
  11172. if( ctx->type.dataType.IsFuncdef() )
  11173. {
  11174. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  11175. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  11176. }
  11177. else
  11178. {
  11179. bool isConst = ctx->type.dataType.IsObjectConst();
  11180. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  11181. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  11182. }
  11183. if( funcs.GetLength() != 1 )
  11184. {
  11185. // The error was reported by MatchFunctions()
  11186. // Dummy value
  11187. ctx->type.SetDummy();
  11188. }
  11189. else
  11190. {
  11191. // Add the default values for arguments not explicitly supplied
  11192. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  11193. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  11194. // is it enough to make sure it is in a local variable?
  11195. // For function pointer we must guarantee that the function is safe, i.e.
  11196. // by first storing the function pointer in a local variable (if it isn't already in one)
  11197. if( r == asSUCCESS )
  11198. {
  11199. Dereference(ctx, true);
  11200. if( ctx->type.dataType.IsFuncdef() )
  11201. {
  11202. if( !ctx->type.isVariable )
  11203. ConvertToVariable(ctx);
  11204. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  11205. ctx->bc.Instr(asBC_PopPtr);
  11206. }
  11207. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  11208. }
  11209. }
  11210. }
  11211. else
  11212. ctx->type.SetDummy();
  11213. // Cleanup
  11214. for( asUINT n = 0; n < args.GetLength(); n++ )
  11215. if( args[n] )
  11216. {
  11217. asDELETE(args[n], asCExprContext);
  11218. }
  11219. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  11220. if( namedArgs[n].ctx )
  11221. {
  11222. asDELETE(namedArgs[n].ctx, asCExprContext);
  11223. }
  11224. }
  11225. return 0;
  11226. }
  11227. int asCCompiler::GetPrecedence(asCScriptNode *op)
  11228. {
  11229. // x ** y
  11230. // x * y, x / y, x % y
  11231. // x + y, x - y
  11232. // x <= y, x < y, x >= y, x > y
  11233. // x = =y, x != y, x xor y, x is y, x !is y
  11234. // x and y
  11235. // x or y
  11236. // The following are not used in this function,
  11237. // but should have lower precedence than the above
  11238. // x ? y : z
  11239. // x = y
  11240. // The expression term have the highest precedence
  11241. if( op->nodeType == snExprTerm )
  11242. return 1;
  11243. // Evaluate operators by token
  11244. int tokenType = op->tokenType;
  11245. if( tokenType == ttStarStar )
  11246. return 0;
  11247. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  11248. return -1;
  11249. if( tokenType == ttPlus || tokenType == ttMinus )
  11250. return -2;
  11251. if( tokenType == ttBitShiftLeft ||
  11252. tokenType == ttBitShiftRight ||
  11253. tokenType == ttBitShiftRightArith )
  11254. return -3;
  11255. if( tokenType == ttAmp )
  11256. return -4;
  11257. if( tokenType == ttBitXor )
  11258. return -5;
  11259. if( tokenType == ttBitOr )
  11260. return -6;
  11261. if( tokenType == ttLessThanOrEqual ||
  11262. tokenType == ttLessThan ||
  11263. tokenType == ttGreaterThanOrEqual ||
  11264. tokenType == ttGreaterThan )
  11265. return -7;
  11266. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  11267. return -8;
  11268. if( tokenType == ttAnd )
  11269. return -9;
  11270. if( tokenType == ttOr )
  11271. return -10;
  11272. // Unknown operator
  11273. asASSERT(false);
  11274. return 0;
  11275. }
  11276. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11277. {
  11278. matches.SetLength(0);
  11279. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  11280. {
  11281. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  11282. // Does the function have arguments enough?
  11283. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  11284. continue;
  11285. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  11286. if( cost != -1 )
  11287. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  11288. }
  11289. return (asUINT)matches.GetLength();
  11290. }
  11291. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11292. {
  11293. // void expressions can match any out parameter, but nothing else
  11294. if( argExpr->IsVoidExpression() )
  11295. {
  11296. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  11297. return 0;
  11298. return -1;
  11299. }
  11300. // Anonymous init lists can only match parameters that can be initialized with a list
  11301. if (argExpr->IsAnonymousInitList())
  11302. {
  11303. if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) ||
  11304. desc->parameterTypes[paramNum].GetBehaviour() == 0 ||
  11305. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0)
  11306. {
  11307. return -1;
  11308. }
  11309. return 0;
  11310. }
  11311. // Can we make the match by implicit conversion?
  11312. asCExprContext ti(engine);
  11313. ti.type = argExpr->type;
  11314. ti.methodName = argExpr->methodName;
  11315. ti.enumValue = argExpr->enumValue;
  11316. ti.exprNode = argExpr->exprNode;
  11317. if( argExpr->type.dataType.IsPrimitive() )
  11318. ti.type.dataType.MakeReference(false);
  11319. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  11320. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  11321. allowObjectConstruct = false;
  11322. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  11323. // If the function parameter is an inout-reference then it must not be possible to call the
  11324. // function with an incorrect argument type, even though the type can normally be converted.
  11325. if( desc->parameterTypes[paramNum].IsReference() &&
  11326. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  11327. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  11328. {
  11329. // Observe, that the below checks are only necessary for when unsafe references have been
  11330. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  11331. // for these value types.
  11332. // Don't allow a primitive to be converted to a reference of another primitive type
  11333. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  11334. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  11335. {
  11336. asASSERT( engine->ep.allowUnsafeReferences );
  11337. return -1;
  11338. }
  11339. // Don't allow an enum to be converted to a reference of another enum type
  11340. if( desc->parameterTypes[paramNum].IsEnumType() &&
  11341. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  11342. {
  11343. asASSERT( engine->ep.allowUnsafeReferences );
  11344. return -1;
  11345. }
  11346. // Don't allow a non-handle expression to be converted to a reference to a handle
  11347. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  11348. !argExpr->type.dataType.IsObjectHandle() )
  11349. {
  11350. asASSERT( engine->ep.allowUnsafeReferences );
  11351. return -1;
  11352. }
  11353. // Don't allow a value type to be converted
  11354. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  11355. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  11356. {
  11357. asASSERT( engine->ep.allowUnsafeReferences );
  11358. return -1;
  11359. }
  11360. }
  11361. // How well does the argument match the function parameter?
  11362. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  11363. return cost;
  11364. // No match is available
  11365. return -1;
  11366. }
  11367. int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  11368. {
  11369. // Reference parameters whose value won't be used don't evaluate the expression
  11370. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  11371. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  11372. {
  11373. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  11374. asCExprContext *orig = asNEW(asCExprContext)(engine);
  11375. if( orig == 0 )
  11376. {
  11377. // Out of memory
  11378. return -1;
  11379. }
  11380. MergeExprBytecodeAndType(orig, arg);
  11381. arg->origExpr = orig;
  11382. }
  11383. int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  11384. if (r < 0)
  11385. return r;
  11386. // arg still holds the original expression for output parameters
  11387. ctx->bc.AddCode(&arg->bc);
  11388. return 0;
  11389. }
  11390. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  11391. {
  11392. DetermineSingleFunc(lctx, node);
  11393. DetermineSingleFunc(rctx, node);
  11394. ctx->exprNode = node;
  11395. // What type of operator is it?
  11396. if( token == ttUnrecognizedToken )
  11397. token = node->tokenType;
  11398. if( token == ttUnrecognizedToken )
  11399. {
  11400. // This happens when the compiler is inferring an assignment
  11401. // operation from another action, for example in preparing a value
  11402. // as a function argument
  11403. token = ttAssignment;
  11404. }
  11405. // boolean operators are not overloadable
  11406. if( token == ttAnd ||
  11407. token == ttOr ||
  11408. token == ttXor )
  11409. return false;
  11410. // Dual operators can also be implemented as class methods
  11411. if( token == ttEqual ||
  11412. token == ttNotEqual )
  11413. {
  11414. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11415. // Find the matching opEquals method
  11416. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11417. if( r == 0 )
  11418. {
  11419. // Try again by switching the order of the operands
  11420. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11421. }
  11422. if( r == 1 )
  11423. {
  11424. if( token == ttNotEqual )
  11425. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  11426. // Success, don't continue
  11427. return true;
  11428. }
  11429. else if( r < 0 )
  11430. {
  11431. // Compiler error, don't continue
  11432. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11433. return true;
  11434. }
  11435. }
  11436. if( token == ttEqual ||
  11437. token == ttNotEqual ||
  11438. token == ttLessThan ||
  11439. token == ttLessThanOrEqual ||
  11440. token == ttGreaterThan ||
  11441. token == ttGreaterThanOrEqual )
  11442. {
  11443. bool swappedOrder = false;
  11444. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11445. // Find the matching opCmp method
  11446. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11447. if( r == 0 )
  11448. {
  11449. // Try again by switching the order of the operands
  11450. swappedOrder = true;
  11451. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11452. }
  11453. if( r == 1 )
  11454. {
  11455. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11456. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11457. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  11458. if( token == ttEqual )
  11459. ctx->bc.Instr(asBC_TZ);
  11460. else if( token == ttNotEqual )
  11461. ctx->bc.Instr(asBC_TNZ);
  11462. else if( (token == ttLessThan && !swappedOrder) ||
  11463. (token == ttGreaterThan && swappedOrder) )
  11464. ctx->bc.Instr(asBC_TS);
  11465. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  11466. (token == ttGreaterThanOrEqual && swappedOrder) )
  11467. ctx->bc.Instr(asBC_TNP);
  11468. else if( (token == ttGreaterThan && !swappedOrder) ||
  11469. (token == ttLessThan && swappedOrder) )
  11470. ctx->bc.Instr(asBC_TP);
  11471. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  11472. (token == ttLessThanOrEqual && swappedOrder) )
  11473. ctx->bc.Instr(asBC_TNS);
  11474. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11475. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  11476. // Success, don't continue
  11477. return true;
  11478. }
  11479. else if( r < 0 )
  11480. {
  11481. // Compiler error, don't continue
  11482. #if AS_SIZEOF_BOOL == 1
  11483. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11484. #else
  11485. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11486. #endif
  11487. return true;
  11488. }
  11489. }
  11490. // The rest of the operators are not commutative, and doesn't require specific return type
  11491. const char *op = 0, *op_r = 0;
  11492. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11493. {
  11494. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  11495. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  11496. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  11497. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  11498. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  11499. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  11500. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  11501. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  11502. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  11503. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  11504. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  11505. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  11506. }
  11507. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  11508. if( op && op_r )
  11509. {
  11510. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11511. // Find the matching operator method
  11512. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  11513. if( r == 0 )
  11514. {
  11515. // Try again by switching the order of the operands, and using the reversed operator
  11516. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  11517. }
  11518. if( r == 1 )
  11519. {
  11520. // Success, don't continue
  11521. return true;
  11522. }
  11523. else if( r < 0 )
  11524. {
  11525. // Compiler error, don't continue
  11526. ctx->type.SetDummy();
  11527. return true;
  11528. }
  11529. }
  11530. // Assignment operators
  11531. op = 0;
  11532. if( isHandle )
  11533. {
  11534. // Only asOBJ_ASHANDLE types can get here
  11535. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  11536. asASSERT( token == ttAssignment );
  11537. if( token == ttAssignment )
  11538. op = "opHndlAssign";
  11539. }
  11540. else
  11541. {
  11542. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11543. {
  11544. case ttAssignment: op = "opAssign"; break;
  11545. case ttAddAssign: op = "opAddAssign"; break;
  11546. case ttSubAssign: op = "opSubAssign"; break;
  11547. case ttMulAssign: op = "opMulAssign"; break;
  11548. case ttDivAssign: op = "opDivAssign"; break;
  11549. case ttModAssign: op = "opModAssign"; break;
  11550. case ttPowAssign: op = "opPowAssign"; break;
  11551. case ttOrAssign: op = "opOrAssign"; break;
  11552. case ttAndAssign: op = "opAndAssign"; break;
  11553. case ttXorAssign: op = "opXorAssign"; break;
  11554. case ttShiftLeftAssign: op = "opShlAssign"; break;
  11555. case ttShiftRightLAssign: op = "opShrAssign"; break;
  11556. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  11557. }
  11558. }
  11559. if( op )
  11560. {
  11561. if( builder->engine->ep.disallowValueAssignForRefType &&
  11562. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  11563. {
  11564. if( token == ttAssignment )
  11565. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  11566. else
  11567. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  11568. // Set a dummy output
  11569. ctx->type.Set(lctx->type.dataType);
  11570. return true;
  11571. }
  11572. // TODO: Shouldn't accept const lvalue with the assignment operators
  11573. // Find the matching operator method
  11574. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  11575. if( r == 1 )
  11576. {
  11577. // Success, don't continue
  11578. return true;
  11579. }
  11580. else if( r < 0 )
  11581. {
  11582. // Compiler error, don't continue
  11583. ctx->type.SetDummy();
  11584. return true;
  11585. }
  11586. }
  11587. // No suitable operator was found
  11588. return false;
  11589. }
  11590. // Returns negative on compile error
  11591. // zero on no matching operator
  11592. // one on matching operator
  11593. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  11594. {
  11595. // Find the matching method
  11596. if( lctx->type.dataType.IsObject() &&
  11597. (!lctx->type.isExplicitHandle ||
  11598. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) &&
  11599. !lctx->type.IsNullConstant() )
  11600. {
  11601. asUINT n;
  11602. // Is the left value a const?
  11603. bool isConst = lctx->type.dataType.IsObjectConst();
  11604. asCArray<int> funcs;
  11605. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  11606. asASSERT(ot);
  11607. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  11608. {
  11609. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11610. asASSERT( func );
  11611. if( func && func->name == methodName &&
  11612. (!specificReturn || func->returnType == returnType) &&
  11613. func->parameterTypes.GetLength() == 1 &&
  11614. (!isConst || func->IsReadOnly()) )
  11615. {
  11616. // Make sure the method is accessible by the module
  11617. if( builder->module->accessMask & func->accessMask )
  11618. {
  11619. funcs.PushLast(func->id);
  11620. }
  11621. }
  11622. }
  11623. // Which is the best matching function?
  11624. asCArray<asSOverloadCandidate> tempFuncs;
  11625. MatchArgument(funcs, tempFuncs, rctx, 0);
  11626. // Find the lowest cost operator(s)
  11627. asCArray<int> ops;
  11628. asUINT bestCost = asUINT(-1);
  11629. for( n = 0; n < tempFuncs.GetLength(); ++n )
  11630. {
  11631. asUINT cost = tempFuncs[n].cost;
  11632. if( cost < bestCost )
  11633. {
  11634. ops.SetLength(0);
  11635. bestCost = cost;
  11636. }
  11637. if( cost == bestCost )
  11638. ops.PushLast(tempFuncs[n].funcId);
  11639. }
  11640. // If the object is not const, then we need to prioritize non-const methods
  11641. if( !isConst )
  11642. FilterConst(ops);
  11643. // Did we find an operator?
  11644. if( ops.GetLength() == 1 )
  11645. {
  11646. // Reserve the variables used in the right expression so the new temporary
  11647. // variable allocated for the left operand isn't accidentally overwritten.
  11648. int l = int(reservedVariables.GetLength());
  11649. rctx->bc.GetVarsUsed(reservedVariables);
  11650. // Process the lctx expression as get accessor
  11651. ProcessPropertyGetAccessor(lctx, node);
  11652. reservedVariables.SetLength(l);
  11653. asCExprContext tmpCtx(engine);
  11654. if (leftToRight)
  11655. {
  11656. // Make sure lctx is in fact a variable. If it is a reference there is no
  11657. // guarantee that the reference will stay alive throughout the evaluation of rctx
  11658. if (!lctx->type.isVariable)
  11659. {
  11660. // Reserve the variables used in the right expression so the new temporary
  11661. // variable allocated for the left operand isn't accidentally overwritten.
  11662. l = int(reservedVariables.GetLength());
  11663. rctx->bc.GetVarsUsed(reservedVariables);
  11664. if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
  11665. {
  11666. // If the application allows unsafe references, then it is not necessary to
  11667. // make a copy of the object, just store the reference as a local variable
  11668. // Allocate a temporary variable as reference to the type
  11669. asCDataType dt = lctx->type.dataType;
  11670. dt.MakeReference(true);
  11671. int offset = AllocateVariable(dt, true, false, true);
  11672. Dereference(lctx, true);
  11673. // Copy the pointer to the temporary variable
  11674. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11675. if (lctx->type.dataType.IsFuncdef())
  11676. lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11677. else
  11678. lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo());
  11679. lctx->type.SetVariable(dt, offset, true);
  11680. }
  11681. else
  11682. {
  11683. if (lctx->type.dataType.SupportHandles())
  11684. lctx->type.dataType.MakeHandle(true);
  11685. PrepareTemporaryVariable(node, lctx);
  11686. }
  11687. reservedVariables.SetLength(l);
  11688. }
  11689. // Move the bytecode for the left operand to a temporary context
  11690. // so we can later make sure this is computed first
  11691. tmpCtx.bc.AddCode(&lctx->bc);
  11692. tmpCtx.bc.Instr(asBC_PopPtr);
  11693. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  11694. // This will be placed after rctx by MakeFunctionCall below
  11695. lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
  11696. // Implicitly dereference handle parameters sent by reference
  11697. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  11698. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  11699. lctx->bc.Instr(asBC_RDSPtr);
  11700. }
  11701. else
  11702. {
  11703. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  11704. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  11705. asCArray<int> usedVars;
  11706. lctx->bc.GetVarsUsed(usedVars);
  11707. asUINT oldReservedVars = reservedVariables.GetLength();
  11708. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  11709. {
  11710. if (rctx->deferredParams[n].argType.isTemporary &&
  11711. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  11712. {
  11713. if (reservedVariables.GetLength() == oldReservedVars)
  11714. reservedVariables.Concatenate(usedVars);
  11715. // Allocate a new variable for the deferred argument
  11716. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  11717. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  11718. rctx->deferredParams[n].argType.stackOffset = short(offset);
  11719. rctx->bc.ExchangeVar(oldVar, offset);
  11720. ReleaseTemporaryVariable(oldVar, 0);
  11721. }
  11722. }
  11723. reservedVariables.SetLength(oldReservedVars);
  11724. }
  11725. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  11726. asCArray<asCExprContext *> args;
  11727. args.PushLast(rctx);
  11728. MergeExprBytecode(ctx, lctx);
  11729. ctx->type = lctx->type;
  11730. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  11731. // Rearrange the bytecode so the left argument is computed first
  11732. if (leftToRight)
  11733. {
  11734. tmpCtx.bc.AddCode(&ctx->bc);
  11735. ctx->bc.AddCode(&tmpCtx.bc);
  11736. }
  11737. // Found matching operator
  11738. return 1;
  11739. }
  11740. else if( ops.GetLength() > 1 )
  11741. {
  11742. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11743. PrintMatchingFuncs(ops, node);
  11744. ctx->type.SetDummy();
  11745. // Compiler error
  11746. return -1;
  11747. }
  11748. }
  11749. // No matching operator
  11750. return 0;
  11751. }
  11752. void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  11753. {
  11754. if( objectType )
  11755. Dereference(ctx, true);
  11756. // Store the expression node for error reporting
  11757. if( ctx->exprNode == 0 )
  11758. ctx->exprNode = node;
  11759. asCByteCode objBC(engine);
  11760. objBC.AddCode(&ctx->bc);
  11761. int r = PrepareFunctionCall(funcId, &ctx->bc, args);
  11762. if (r < 0)
  11763. return;
  11764. // Verify if any of the args variable offsets are used in the other code.
  11765. // If they are exchange the offset for a new one
  11766. asUINT n;
  11767. for( n = 0; n < args.GetLength(); n++ )
  11768. {
  11769. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  11770. {
  11771. // Release the current temporary variable
  11772. ReleaseTemporaryVariable(args[n]->type, 0);
  11773. asCDataType dt = args[n]->type.dataType;
  11774. dt.MakeReference(false);
  11775. int l = int(reservedVariables.GetLength());
  11776. objBC.GetVarsUsed(reservedVariables);
  11777. ctx->bc.GetVarsUsed(reservedVariables);
  11778. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  11779. reservedVariables.SetLength(l);
  11780. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  11781. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  11782. args[n]->type.stackOffset = (short)newOffset;
  11783. args[n]->type.isTemporary = true;
  11784. args[n]->type.isVariable = true;
  11785. }
  11786. }
  11787. // If the function will return a value type on the stack, then we must allocate space
  11788. // for that here and push the address on the stack as a hidden argument to the function
  11789. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  11790. if( func->DoesReturnOnStack() )
  11791. {
  11792. asASSERT(!useVariable);
  11793. useVariable = true;
  11794. stackOffset = AllocateVariable(func->returnType, true);
  11795. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  11796. }
  11797. ctx->bc.AddCode(&objBC);
  11798. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  11799. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  11800. }
  11801. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  11802. {
  11803. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  11804. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  11805. {
  11806. Error(TXT_INVALID_OP_ON_METHOD, node);
  11807. return -1;
  11808. }
  11809. // Don't allow any operators on void expressions
  11810. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  11811. {
  11812. Error(TXT_VOID_CANT_BE_OPERAND, node);
  11813. return -1;
  11814. }
  11815. if( op == ttUnrecognizedToken )
  11816. op = node->tokenType;
  11817. IsVariableInitialized(&lctx->type, node);
  11818. IsVariableInitialized(&rctx->type, node);
  11819. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  11820. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  11821. op == ttIs || op == ttNotIs )
  11822. {
  11823. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  11824. return 0;
  11825. }
  11826. else
  11827. {
  11828. // Compile an overloaded operator for the two operands
  11829. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  11830. return 0;
  11831. // If both operands are objects, then we shouldn't continue
  11832. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  11833. {
  11834. asCString str;
  11835. 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());
  11836. Error(str, node);
  11837. ctx->type.SetDummy();
  11838. return -1;
  11839. }
  11840. // Process the property get accessors (if any)
  11841. ProcessPropertyGetAccessor(lctx, node);
  11842. ProcessPropertyGetAccessor(rctx, node);
  11843. // Make sure we have two variables or constants
  11844. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  11845. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  11846. // Make sure lctx doesn't end up with a variable used in rctx
  11847. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  11848. {
  11849. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  11850. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  11851. ReleaseTemporaryVariable(offset, 0);
  11852. }
  11853. // Math operators
  11854. // + - * / % ** += -= *= /= %= **=
  11855. if( op == ttPlus || op == ttAddAssign ||
  11856. op == ttMinus || op == ttSubAssign ||
  11857. op == ttStar || op == ttMulAssign ||
  11858. op == ttSlash || op == ttDivAssign ||
  11859. op == ttPercent || op == ttModAssign ||
  11860. op == ttStarStar || op == ttPowAssign )
  11861. {
  11862. CompileMathOperator(node, lctx, rctx, ctx, op);
  11863. return 0;
  11864. }
  11865. // Bitwise operators
  11866. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  11867. if( op == ttAmp || op == ttAndAssign ||
  11868. op == ttBitOr || op == ttOrAssign ||
  11869. op == ttBitXor || op == ttXorAssign ||
  11870. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  11871. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  11872. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11873. {
  11874. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  11875. return 0;
  11876. }
  11877. // Comparison operators
  11878. // == != < > <= >=
  11879. if( op == ttEqual || op == ttNotEqual ||
  11880. op == ttLessThan || op == ttLessThanOrEqual ||
  11881. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  11882. {
  11883. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  11884. return 0;
  11885. }
  11886. // Boolean operators
  11887. // && || ^^
  11888. if( op == ttAnd || op == ttOr || op == ttXor )
  11889. {
  11890. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  11891. return 0;
  11892. }
  11893. }
  11894. asASSERT(false);
  11895. return -1;
  11896. }
  11897. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  11898. {
  11899. int l = int(reservedVariables.GetLength());
  11900. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  11901. ConvertToTempVariable(ctx);
  11902. reservedVariables.SetLength(l);
  11903. }
  11904. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  11905. {
  11906. // This is only used for primitive types and null handles
  11907. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  11908. ConvertToVariable(ctx);
  11909. if( !ctx->type.isTemporary )
  11910. {
  11911. if( ctx->type.dataType.IsPrimitive() )
  11912. {
  11913. // Copy the variable to a temporary variable
  11914. int offset = AllocateVariable(ctx->type.dataType, true);
  11915. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11916. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  11917. else
  11918. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  11919. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11920. }
  11921. else
  11922. {
  11923. // We should never get here
  11924. asASSERT(false);
  11925. }
  11926. }
  11927. }
  11928. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  11929. {
  11930. // We should never get here while the context is still an unprocessed property accessor
  11931. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  11932. int offset;
  11933. if( !ctx->type.isVariable &&
  11934. (ctx->type.dataType.IsObjectHandle() ||
  11935. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  11936. {
  11937. offset = AllocateVariable(ctx->type.dataType, true);
  11938. if( ctx->type.IsNullConstant() )
  11939. {
  11940. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  11941. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  11942. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  11943. }
  11944. else
  11945. {
  11946. Dereference(ctx, true);
  11947. // Copy the object handle to a variable
  11948. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11949. if( ctx->type.dataType.IsFuncdef() )
  11950. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11951. else
  11952. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  11953. ctx->bc.Instr(asBC_PopPtr);
  11954. }
  11955. // As this is an object the reference must be placed on the stack
  11956. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11957. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11958. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11959. ctx->type.dataType.MakeHandle(true);
  11960. ctx->type.dataType.MakeReference(true);
  11961. }
  11962. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  11963. ctx->type.dataType.IsPrimitive() )
  11964. {
  11965. if( ctx->type.isConstant )
  11966. {
  11967. offset = AllocateVariable(ctx->type.dataType, true);
  11968. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11969. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  11970. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11971. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  11972. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  11973. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  11974. else
  11975. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  11976. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11977. return;
  11978. }
  11979. else
  11980. {
  11981. asASSERT(ctx->type.dataType.IsPrimitive());
  11982. asASSERT(ctx->type.dataType.IsReference());
  11983. ctx->type.dataType.MakeReference(false);
  11984. offset = AllocateVariable(ctx->type.dataType, true);
  11985. // Read the value from the address in the register directly into the variable
  11986. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11987. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  11988. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11989. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  11990. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11991. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  11992. else
  11993. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  11994. }
  11995. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11996. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11997. }
  11998. }
  11999. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12000. {
  12001. int l = int(reservedVariables.GetLength());
  12002. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12003. ConvertToVariable(ctx);
  12004. reservedVariables.SetLength(l);
  12005. }
  12006. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  12007. {
  12008. asCArray<int> funcs;
  12009. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  12010. if( ot )
  12011. {
  12012. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  12013. {
  12014. // Consider only implicit casts
  12015. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  12016. if( func->name == "opImplConv" &&
  12017. func->returnType.IsPrimitive() &&
  12018. func->parameterTypes.GetLength() == 0 )
  12019. funcs.PushLast(ot->methods[n]);
  12020. }
  12021. // Use the one with the highest precision
  12022. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  12023. while( funcs.GetLength() > 1 )
  12024. {
  12025. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  12026. int value1 = 11, value2 = 11;
  12027. for( asUINT i = 0; i < 10; i++ )
  12028. {
  12029. if( returnType == match[i] )
  12030. {
  12031. value1 = i;
  12032. break;
  12033. }
  12034. }
  12035. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  12036. {
  12037. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  12038. for( asUINT i = 0; i < 10; i++ )
  12039. {
  12040. if( returnType == match[i] )
  12041. {
  12042. value2 = i;
  12043. break;
  12044. }
  12045. }
  12046. if( value2 >= value1 )
  12047. {
  12048. // Remove this and continue searching
  12049. funcs.RemoveIndexUnordered(n--);
  12050. }
  12051. else
  12052. {
  12053. // Remove the first, and start over
  12054. funcs.RemoveIndexUnordered(0);
  12055. break;
  12056. }
  12057. }
  12058. }
  12059. // Do the conversion
  12060. if( funcs.GetLength() )
  12061. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  12062. }
  12063. }
  12064. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12065. {
  12066. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12067. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  12068. // If either operand is a non-primitive then use the primitive type
  12069. if( !lctx->type.dataType.IsPrimitive() )
  12070. {
  12071. int l = int(reservedVariables.GetLength());
  12072. rctx->bc.GetVarsUsed(reservedVariables);
  12073. ImplicitConvObjectToBestMathType(lctx, node);
  12074. reservedVariables.SetLength(l);
  12075. }
  12076. if( !rctx->type.dataType.IsPrimitive() )
  12077. {
  12078. int l = int(reservedVariables.GetLength());
  12079. lctx->bc.GetVarsUsed(reservedVariables);
  12080. ImplicitConvObjectToBestMathType(rctx, node);
  12081. reservedVariables.SetLength(l);
  12082. }
  12083. // Both types must now be primitives. Implicitly convert them so they match
  12084. asCDataType to;
  12085. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12086. to.SetTokenType(ttDouble);
  12087. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12088. to.SetTokenType(ttFloat);
  12089. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12090. {
  12091. // Convert to int64 if both are signed or if one is non-constant and signed
  12092. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12093. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12094. to.SetTokenType(ttInt64);
  12095. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12096. to.SetTokenType(ttUInt64);
  12097. else
  12098. to.SetTokenType(ttInt64);
  12099. }
  12100. else
  12101. {
  12102. // Convert to int32 if both are signed or if one is non-constant and signed
  12103. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12104. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12105. to.SetTokenType(ttInt);
  12106. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12107. to.SetTokenType(ttUInt);
  12108. else
  12109. to.SetTokenType(ttInt);
  12110. }
  12111. // If doing an operation with double constant and float variable, the constant should be converted to float
  12112. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12113. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12114. to.SetTokenType(ttFloat);
  12115. if( op == ttUnrecognizedToken )
  12116. op = node->tokenType;
  12117. // If integer division is disabled, convert to floating-point
  12118. if( engine->ep.disableIntegerDivision &&
  12119. (op == ttSlash || op == ttDivAssign) &&
  12120. (to.IsIntegerType() || to.IsUnsignedType()) )
  12121. {
  12122. // Use double to avoid losing precision when dividing with 32bit ints
  12123. // For 64bit ints there is unfortunately no greater type so with those
  12124. // there is still a risk of loosing precision
  12125. to.SetTokenType(ttDouble);
  12126. }
  12127. // Do the actual conversion
  12128. int l = int(reservedVariables.GetLength());
  12129. rctx->bc.GetVarsUsed(reservedVariables);
  12130. lctx->bc.GetVarsUsed(reservedVariables);
  12131. if( lctx->type.dataType.IsReference() )
  12132. ConvertToVariable(lctx);
  12133. if( rctx->type.dataType.IsReference() )
  12134. ConvertToVariable(rctx);
  12135. if( to.IsPrimitive() )
  12136. {
  12137. // ttStarStar allows an integer, right-hand operand and a double
  12138. // left-hand operand.
  12139. if( (op == ttStarStar || op == ttPowAssign) &&
  12140. lctx->type.dataType.IsDoubleType() &&
  12141. (rctx->type.dataType.IsIntegerType() ||
  12142. rctx->type.dataType.IsUnsignedType()) )
  12143. {
  12144. to.SetTokenType(ttInt);
  12145. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12146. to.SetTokenType(ttDouble);
  12147. }
  12148. else
  12149. {
  12150. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12151. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12152. }
  12153. }
  12154. reservedVariables.SetLength(l);
  12155. // Verify that the conversion was successful
  12156. if( !lctx->type.dataType.IsIntegerType() &&
  12157. !lctx->type.dataType.IsUnsignedType() &&
  12158. !lctx->type.dataType.IsFloatType() &&
  12159. !lctx->type.dataType.IsDoubleType() )
  12160. {
  12161. asCString str;
  12162. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12163. Error(str, node);
  12164. ctx->type.SetDummy();
  12165. return;
  12166. }
  12167. if( !rctx->type.dataType.IsIntegerType() &&
  12168. !rctx->type.dataType.IsUnsignedType() &&
  12169. !rctx->type.dataType.IsFloatType() &&
  12170. !rctx->type.dataType.IsDoubleType() )
  12171. {
  12172. asCString str;
  12173. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12174. Error(str, node);
  12175. ctx->type.SetDummy();
  12176. return;
  12177. }
  12178. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12179. // Verify if we are dividing with a constant zero
  12180. if( rctx->type.isConstant &&
  12181. (op == ttSlash || op == ttDivAssign ||
  12182. op == ttPercent || op == ttModAssign) &&
  12183. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  12184. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  12185. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  12186. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  12187. {
  12188. Error(TXT_DIVIDE_BY_ZERO, node);
  12189. }
  12190. if( !isConstant )
  12191. {
  12192. ConvertToVariableNotIn(lctx, rctx);
  12193. ConvertToVariableNotIn(rctx, lctx);
  12194. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12195. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12196. if( op == ttAddAssign || op == ttSubAssign ||
  12197. op == ttMulAssign || op == ttDivAssign ||
  12198. op == ttModAssign || op == ttPowAssign )
  12199. {
  12200. // Merge the operands in the different order so that they are evaluated correctly
  12201. MergeExprBytecode(ctx, rctx);
  12202. MergeExprBytecode(ctx, lctx);
  12203. // We must not process the deferred parameters yet, as
  12204. // it may overwrite the lvalue kept in the register
  12205. }
  12206. else
  12207. {
  12208. MergeExprBytecode(ctx, lctx);
  12209. MergeExprBytecode(ctx, rctx);
  12210. ProcessDeferredParams(ctx);
  12211. }
  12212. asEBCInstr instruction = asBC_ADDi;
  12213. if( lctx->type.dataType.IsIntegerType() ||
  12214. lctx->type.dataType.IsUnsignedType() )
  12215. {
  12216. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12217. {
  12218. if( op == ttPlus || op == ttAddAssign )
  12219. instruction = asBC_ADDi;
  12220. else if( op == ttMinus || op == ttSubAssign )
  12221. instruction = asBC_SUBi;
  12222. else if( op == ttStar || op == ttMulAssign )
  12223. instruction = asBC_MULi;
  12224. else if( op == ttSlash || op == ttDivAssign )
  12225. {
  12226. if( lctx->type.dataType.IsIntegerType() )
  12227. instruction = asBC_DIVi;
  12228. else
  12229. instruction = asBC_DIVu;
  12230. }
  12231. else if( op == ttPercent || op == ttModAssign )
  12232. {
  12233. if( lctx->type.dataType.IsIntegerType() )
  12234. instruction = asBC_MODi;
  12235. else
  12236. instruction = asBC_MODu;
  12237. }
  12238. else if( op == ttStarStar || op == ttPowAssign )
  12239. {
  12240. if( lctx->type.dataType.IsIntegerType() )
  12241. instruction = asBC_POWi;
  12242. else
  12243. instruction = asBC_POWu;
  12244. }
  12245. }
  12246. else
  12247. {
  12248. if( op == ttPlus || op == ttAddAssign )
  12249. instruction = asBC_ADDi64;
  12250. else if( op == ttMinus || op == ttSubAssign )
  12251. instruction = asBC_SUBi64;
  12252. else if( op == ttStar || op == ttMulAssign )
  12253. instruction = asBC_MULi64;
  12254. else if( op == ttSlash || op == ttDivAssign )
  12255. {
  12256. if( lctx->type.dataType.IsIntegerType() )
  12257. instruction = asBC_DIVi64;
  12258. else
  12259. instruction = asBC_DIVu64;
  12260. }
  12261. else if( op == ttPercent || op == ttModAssign )
  12262. {
  12263. if( lctx->type.dataType.IsIntegerType() )
  12264. instruction = asBC_MODi64;
  12265. else
  12266. instruction = asBC_MODu64;
  12267. }
  12268. else if( op == ttStarStar || op == ttPowAssign )
  12269. {
  12270. if( lctx->type.dataType.IsIntegerType() )
  12271. instruction = asBC_POWi64;
  12272. else
  12273. instruction = asBC_POWu64;
  12274. }
  12275. }
  12276. }
  12277. else if( lctx->type.dataType.IsFloatType() )
  12278. {
  12279. if( op == ttPlus || op == ttAddAssign )
  12280. instruction = asBC_ADDf;
  12281. else if( op == ttMinus || op == ttSubAssign )
  12282. instruction = asBC_SUBf;
  12283. else if( op == ttStar || op == ttMulAssign )
  12284. instruction = asBC_MULf;
  12285. else if( op == ttSlash || op == ttDivAssign )
  12286. instruction = asBC_DIVf;
  12287. else if( op == ttPercent || op == ttModAssign )
  12288. instruction = asBC_MODf;
  12289. else if( op == ttStarStar || op == ttPowAssign )
  12290. instruction = asBC_POWf;
  12291. }
  12292. else if( lctx->type.dataType.IsDoubleType() )
  12293. {
  12294. if( rctx->type.dataType.IsIntegerType() )
  12295. {
  12296. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12297. if( op == ttStarStar || op == ttPowAssign )
  12298. instruction = asBC_POWdi;
  12299. else
  12300. asASSERT(false); // Should not be possible
  12301. }
  12302. else
  12303. {
  12304. if( op == ttPlus || op == ttAddAssign )
  12305. instruction = asBC_ADDd;
  12306. else if( op == ttMinus || op == ttSubAssign )
  12307. instruction = asBC_SUBd;
  12308. else if( op == ttStar || op == ttMulAssign )
  12309. instruction = asBC_MULd;
  12310. else if( op == ttSlash || op == ttDivAssign )
  12311. instruction = asBC_DIVd;
  12312. else if( op == ttPercent || op == ttModAssign )
  12313. instruction = asBC_MODd;
  12314. else if( op == ttStarStar || op == ttPowAssign )
  12315. instruction = asBC_POWd;
  12316. }
  12317. }
  12318. else
  12319. {
  12320. // Shouldn't be possible
  12321. asASSERT(false);
  12322. }
  12323. // Do the operation
  12324. int a = AllocateVariable(lctx->type.dataType, true);
  12325. int b = lctx->type.stackOffset;
  12326. int c = rctx->type.stackOffset;
  12327. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12328. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12329. }
  12330. else
  12331. {
  12332. // Both values are constants
  12333. if( lctx->type.dataType.IsIntegerType() ||
  12334. lctx->type.dataType.IsUnsignedType() )
  12335. {
  12336. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12337. {
  12338. int v = 0;
  12339. if( op == ttPlus )
  12340. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  12341. else if( op == ttMinus )
  12342. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12343. else if( op == ttStar )
  12344. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  12345. else if( op == ttSlash )
  12346. {
  12347. // TODO: Should probably report an error, rather than silently convert the value to 0
  12348. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12349. v = 0;
  12350. else
  12351. if( lctx->type.dataType.IsIntegerType() )
  12352. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  12353. else
  12354. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  12355. }
  12356. else if( op == ttPercent )
  12357. {
  12358. // TODO: Should probably report an error, rather than silently convert the value to 0
  12359. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12360. v = 0;
  12361. else
  12362. if( lctx->type.dataType.IsIntegerType() )
  12363. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  12364. else
  12365. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  12366. }
  12367. else if( op == ttStarStar )
  12368. {
  12369. bool isOverflow;
  12370. if( lctx->type.dataType.IsIntegerType() )
  12371. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  12372. else
  12373. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  12374. if( isOverflow )
  12375. Error(TXT_POW_OVERFLOW, node);
  12376. }
  12377. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12378. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12379. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  12380. ctx->type.dataType.SetTokenType(ttInt);
  12381. }
  12382. else
  12383. {
  12384. asQWORD v = 0;
  12385. if( op == ttPlus )
  12386. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  12387. else if( op == ttMinus )
  12388. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12389. else if( op == ttStar )
  12390. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  12391. else if( op == ttSlash )
  12392. {
  12393. // TODO: Should probably report an error, rather than silently convert the value to 0
  12394. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12395. v = 0;
  12396. else
  12397. if( lctx->type.dataType.IsIntegerType() )
  12398. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  12399. else
  12400. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  12401. }
  12402. else if( op == ttPercent )
  12403. {
  12404. // TODO: Should probably report an error, rather than silently convert the value to 0
  12405. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12406. v = 0;
  12407. else
  12408. if( lctx->type.dataType.IsIntegerType() )
  12409. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  12410. else
  12411. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  12412. }
  12413. else if( op == ttStarStar )
  12414. {
  12415. bool isOverflow;
  12416. if( lctx->type.dataType.IsIntegerType() )
  12417. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  12418. else
  12419. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  12420. if( isOverflow )
  12421. Error(TXT_POW_OVERFLOW, node);
  12422. }
  12423. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12424. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12425. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  12426. ctx->type.dataType.SetTokenType(ttInt64);
  12427. }
  12428. }
  12429. else if( lctx->type.dataType.IsFloatType() )
  12430. {
  12431. float v = 0.0f;
  12432. if( op == ttPlus )
  12433. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  12434. else if( op == ttMinus )
  12435. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12436. else if( op == ttStar )
  12437. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  12438. else if( op == ttSlash )
  12439. {
  12440. if( rctx->type.GetConstantF() == 0 )
  12441. v = 0;
  12442. else
  12443. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  12444. }
  12445. else if( op == ttPercent )
  12446. {
  12447. if( rctx->type.GetConstantF() == 0 )
  12448. v = 0;
  12449. else
  12450. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12451. }
  12452. else if( op == ttStarStar )
  12453. {
  12454. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12455. if( v == HUGE_VAL )
  12456. Error(TXT_POW_OVERFLOW, node);
  12457. }
  12458. ctx->type.SetConstantF(lctx->type.dataType, v);
  12459. }
  12460. else if( lctx->type.dataType.IsDoubleType() )
  12461. {
  12462. double v = 0.0;
  12463. if( rctx->type.dataType.IsIntegerType() )
  12464. {
  12465. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12466. if( op == ttStarStar || op == ttPowAssign )
  12467. {
  12468. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  12469. if( v == HUGE_VAL )
  12470. Error(TXT_POW_OVERFLOW, node);
  12471. }
  12472. else
  12473. asASSERT(false); // Should not be possible
  12474. }
  12475. else
  12476. {
  12477. if( op == ttPlus )
  12478. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  12479. else if( op == ttMinus )
  12480. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12481. else if( op == ttStar )
  12482. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  12483. else if( op == ttSlash )
  12484. {
  12485. if( rctx->type.GetConstantD() == 0 )
  12486. v = 0;
  12487. else
  12488. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  12489. }
  12490. else if( op == ttPercent )
  12491. {
  12492. if( rctx->type.GetConstantD() == 0 )
  12493. v = 0;
  12494. else
  12495. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12496. }
  12497. else if( op == ttStarStar )
  12498. {
  12499. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12500. if( v == HUGE_VAL )
  12501. Error(TXT_POW_OVERFLOW, node);
  12502. }
  12503. }
  12504. ctx->type.SetConstantD(lctx->type.dataType, v);
  12505. }
  12506. else
  12507. {
  12508. // Shouldn't be possible
  12509. asASSERT(false);
  12510. }
  12511. }
  12512. }
  12513. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12514. {
  12515. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12516. if( op == ttUnrecognizedToken )
  12517. op = node->tokenType;
  12518. if( op == ttAmp || op == ttAndAssign ||
  12519. op == ttBitOr || op == ttOrAssign ||
  12520. op == ttBitXor || op == ttXorAssign )
  12521. {
  12522. // Also do not permit float/double to be implicitly converted to integer in this case
  12523. // as the user may think the result is a bitwise operation on the float value but it's not
  12524. if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType())
  12525. {
  12526. asCString str;
  12527. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12528. Error(str, node);
  12529. // Set an integer value and allow the compiler to continue
  12530. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12531. return;
  12532. }
  12533. if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType())
  12534. {
  12535. asCString str;
  12536. str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12537. Error(str, node);
  12538. // Set an integer value and allow the compiler to continue
  12539. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12540. return;
  12541. }
  12542. // Convert left hand operand to integer if it's not already one
  12543. asCDataType to;
  12544. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  12545. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12546. to.SetTokenType(ttInt64);
  12547. else
  12548. to.SetTokenType(ttInt);
  12549. // Do the actual conversion (keep sign/unsigned if possible)
  12550. int l = int(reservedVariables.GetLength());
  12551. rctx->bc.GetVarsUsed(reservedVariables);
  12552. if( lctx->type.dataType.IsUnsignedType() )
  12553. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12554. else
  12555. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12556. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12557. reservedVariables.SetLength(l);
  12558. // Verify that the conversion was successful
  12559. if( lctx->type.dataType != to )
  12560. {
  12561. asCString str;
  12562. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12563. Error(str, node);
  12564. }
  12565. // Convert right hand operand to same size as left hand
  12566. l = int(reservedVariables.GetLength());
  12567. lctx->bc.GetVarsUsed(reservedVariables);
  12568. if( rctx->type.dataType.IsUnsignedType() )
  12569. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12570. else
  12571. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12572. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12573. reservedVariables.SetLength(l);
  12574. if( rctx->type.dataType != to )
  12575. {
  12576. asCString str;
  12577. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12578. Error(str, node);
  12579. }
  12580. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12581. if( !isConstant )
  12582. {
  12583. ConvertToVariableNotIn(lctx, rctx);
  12584. ConvertToVariableNotIn(rctx, lctx);
  12585. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12586. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12587. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  12588. {
  12589. // Compound assignments execute the right hand value first
  12590. MergeExprBytecode(ctx, rctx);
  12591. MergeExprBytecode(ctx, lctx);
  12592. }
  12593. else
  12594. {
  12595. MergeExprBytecode(ctx, lctx);
  12596. MergeExprBytecode(ctx, rctx);
  12597. }
  12598. ProcessDeferredParams(ctx);
  12599. asEBCInstr instruction = asBC_BAND;
  12600. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12601. {
  12602. if( op == ttAmp || op == ttAndAssign )
  12603. instruction = asBC_BAND;
  12604. else if( op == ttBitOr || op == ttOrAssign )
  12605. instruction = asBC_BOR;
  12606. else if( op == ttBitXor || op == ttXorAssign )
  12607. instruction = asBC_BXOR;
  12608. }
  12609. else
  12610. {
  12611. if( op == ttAmp || op == ttAndAssign )
  12612. instruction = asBC_BAND64;
  12613. else if( op == ttBitOr || op == ttOrAssign )
  12614. instruction = asBC_BOR64;
  12615. else if( op == ttBitXor || op == ttXorAssign )
  12616. instruction = asBC_BXOR64;
  12617. }
  12618. // Do the operation
  12619. int a = AllocateVariable(lctx->type.dataType, true);
  12620. int b = lctx->type.stackOffset;
  12621. int c = rctx->type.stackOffset;
  12622. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12623. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12624. }
  12625. else
  12626. {
  12627. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12628. {
  12629. asQWORD v = 0;
  12630. if( op == ttAmp )
  12631. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  12632. else if( op == ttBitOr )
  12633. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  12634. else if( op == ttBitXor )
  12635. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  12636. // Remember the result
  12637. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12638. }
  12639. else
  12640. {
  12641. asDWORD v = 0;
  12642. if( op == ttAmp )
  12643. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  12644. else if( op == ttBitOr )
  12645. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  12646. else if( op == ttBitXor )
  12647. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  12648. // Remember the result
  12649. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12650. }
  12651. }
  12652. }
  12653. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12654. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12655. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12656. {
  12657. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  12658. // Also do not permit float/double to be implicitly converted to integer in this case
  12659. if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() )
  12660. {
  12661. asCString str;
  12662. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12663. Error(str, node);
  12664. // Set an integer value and allow the compiler to continue
  12665. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12666. return;
  12667. }
  12668. // Convert left hand operand to integer if it's not already one
  12669. asCDataType to = lctx->type.dataType;
  12670. if( lctx->type.dataType.IsUnsignedType() &&
  12671. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  12672. {
  12673. // Upgrade to 32bit
  12674. to = asCDataType::CreatePrimitive(ttUInt, false);
  12675. }
  12676. else if( !lctx->type.dataType.IsUnsignedType() )
  12677. {
  12678. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  12679. to = asCDataType::CreatePrimitive(ttInt64, false);
  12680. else
  12681. to = asCDataType::CreatePrimitive(ttInt, false);
  12682. }
  12683. // Do the actual conversion
  12684. int l = int(reservedVariables.GetLength());
  12685. rctx->bc.GetVarsUsed(reservedVariables);
  12686. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12687. reservedVariables.SetLength(l);
  12688. // Verify that the conversion was successful
  12689. if( lctx->type.dataType != to )
  12690. {
  12691. asCString str;
  12692. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12693. Error(str, node);
  12694. }
  12695. // Right operand must be 32bit uint
  12696. l = int(reservedVariables.GetLength());
  12697. lctx->bc.GetVarsUsed(reservedVariables);
  12698. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  12699. reservedVariables.SetLength(l);
  12700. if( !rctx->type.dataType.IsUnsignedType() )
  12701. {
  12702. asCString str;
  12703. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  12704. Error(str, node);
  12705. }
  12706. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12707. if( !isConstant )
  12708. {
  12709. ConvertToVariableNotIn(lctx, rctx);
  12710. ConvertToVariableNotIn(rctx, lctx);
  12711. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12712. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12713. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  12714. {
  12715. // Compound assignments execute the right hand value first
  12716. MergeExprBytecode(ctx, rctx);
  12717. MergeExprBytecode(ctx, lctx);
  12718. }
  12719. else
  12720. {
  12721. MergeExprBytecode(ctx, lctx);
  12722. MergeExprBytecode(ctx, rctx);
  12723. }
  12724. ProcessDeferredParams(ctx);
  12725. asEBCInstr instruction = asBC_BSLL;
  12726. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12727. {
  12728. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12729. instruction = asBC_BSLL;
  12730. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12731. instruction = asBC_BSRL;
  12732. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12733. instruction = asBC_BSRA;
  12734. }
  12735. else
  12736. {
  12737. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12738. instruction = asBC_BSLL64;
  12739. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12740. instruction = asBC_BSRL64;
  12741. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12742. instruction = asBC_BSRA64;
  12743. }
  12744. // Do the operation
  12745. int a = AllocateVariable(lctx->type.dataType, true);
  12746. int b = lctx->type.stackOffset;
  12747. int c = rctx->type.stackOffset;
  12748. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12749. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12750. }
  12751. else
  12752. {
  12753. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12754. {
  12755. asDWORD v = 0;
  12756. if( op == ttBitShiftLeft )
  12757. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  12758. else if( op == ttBitShiftRight )
  12759. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  12760. else if( op == ttBitShiftRightArith )
  12761. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  12762. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12763. }
  12764. else
  12765. {
  12766. asQWORD v = 0;
  12767. if( op == ttBitShiftLeft )
  12768. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  12769. else if( op == ttBitShiftRight )
  12770. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  12771. else if( op == ttBitShiftRightArith )
  12772. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  12773. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12774. }
  12775. }
  12776. }
  12777. }
  12778. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12779. {
  12780. // Both operands must be of the same type
  12781. // If either operand is a non-primitive then first convert them to the best number type
  12782. if( !lctx->type.dataType.IsPrimitive() )
  12783. {
  12784. int l = int(reservedVariables.GetLength());
  12785. rctx->bc.GetVarsUsed(reservedVariables);
  12786. ImplicitConvObjectToBestMathType(lctx, node);
  12787. reservedVariables.SetLength(l);
  12788. }
  12789. if( !rctx->type.dataType.IsPrimitive() )
  12790. {
  12791. int l = int(reservedVariables.GetLength());
  12792. lctx->bc.GetVarsUsed(reservedVariables);
  12793. ImplicitConvObjectToBestMathType(rctx, node);
  12794. reservedVariables.SetLength(l);
  12795. }
  12796. // Implicitly convert the operands to matching types
  12797. asCDataType to;
  12798. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12799. to.SetTokenType(ttDouble);
  12800. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12801. to.SetTokenType(ttFloat);
  12802. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12803. {
  12804. // Convert to int64 if both are signed or if one is non-constant and signed
  12805. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12806. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12807. to.SetTokenType(ttInt64);
  12808. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12809. to.SetTokenType(ttUInt64);
  12810. else
  12811. to.SetTokenType(ttInt64);
  12812. }
  12813. else
  12814. {
  12815. // Convert to int32 if both are signed or if one is non-constant and signed
  12816. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12817. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12818. to.SetTokenType(ttInt);
  12819. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12820. to.SetTokenType(ttUInt);
  12821. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  12822. to.SetTokenType(ttBool);
  12823. else
  12824. to.SetTokenType(ttInt);
  12825. }
  12826. // If doing an operation with double constant and float variable, the constant should be converted to float
  12827. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12828. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12829. to.SetTokenType(ttFloat);
  12830. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  12831. // Do we have a mismatch between the sign of the operand?
  12832. bool signMismatch = false;
  12833. for( int n = 0; !signMismatch && n < 2; n++ )
  12834. {
  12835. asCExprContext *opCtx = n ? rctx : lctx;
  12836. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  12837. {
  12838. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  12839. signMismatch = true;
  12840. if( opCtx->type.isConstant )
  12841. {
  12842. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  12843. {
  12844. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  12845. signMismatch = false;
  12846. }
  12847. else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
  12848. {
  12849. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  12850. signMismatch = false;
  12851. }
  12852. else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
  12853. {
  12854. if (!(opCtx->type.GetConstantW() & (1 << 15)))
  12855. signMismatch = false;
  12856. }
  12857. else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
  12858. {
  12859. if (!(opCtx->type.GetConstantB() & (1 << 7)))
  12860. signMismatch = false;
  12861. }
  12862. // It's not necessary to check for floats or double, because if
  12863. // it was then the types for the conversion will never be unsigned
  12864. }
  12865. }
  12866. }
  12867. // Check for signed/unsigned mismatch
  12868. if( signMismatch )
  12869. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  12870. // Attempt to resolve ambiguous enumerations
  12871. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  12872. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  12873. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  12874. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  12875. // Do the actual conversion
  12876. int l = int(reservedVariables.GetLength());
  12877. rctx->bc.GetVarsUsed(reservedVariables);
  12878. if( lctx->type.dataType.IsReference() )
  12879. ConvertToVariable(lctx);
  12880. if( rctx->type.dataType.IsReference() )
  12881. ConvertToVariable(rctx);
  12882. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12883. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12884. reservedVariables.SetLength(l);
  12885. // Verify that the conversion was successful
  12886. bool ok = true;
  12887. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  12888. {
  12889. asCString str;
  12890. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12891. Error(str, node);
  12892. ok = false;
  12893. }
  12894. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  12895. {
  12896. asCString str;
  12897. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12898. Error(str, node);
  12899. ok = false;
  12900. }
  12901. if( !ok )
  12902. {
  12903. // It wasn't possible to get two valid operands, so we just return
  12904. // a boolean result and let the compiler continue.
  12905. #if AS_SIZEOF_BOOL == 1
  12906. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12907. #else
  12908. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12909. #endif
  12910. return;
  12911. }
  12912. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12913. if( op == ttUnrecognizedToken )
  12914. op = node->tokenType;
  12915. if( !isConstant )
  12916. {
  12917. if( to.IsBooleanType() )
  12918. {
  12919. if( op == ttEqual || op == ttNotEqual )
  12920. {
  12921. // Must convert to temporary variable, because we are changing the value before comparison
  12922. ConvertToTempVariableNotIn(lctx, rctx);
  12923. ConvertToTempVariableNotIn(rctx, lctx);
  12924. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12925. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12926. // Make sure they are equal if not false
  12927. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  12928. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  12929. MergeExprBytecode(ctx, lctx);
  12930. MergeExprBytecode(ctx, rctx);
  12931. ProcessDeferredParams(ctx);
  12932. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12933. int b = lctx->type.stackOffset;
  12934. int c = rctx->type.stackOffset;
  12935. if( op == ttEqual )
  12936. {
  12937. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12938. ctx->bc.Instr(asBC_TZ);
  12939. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12940. }
  12941. else if( op == ttNotEqual )
  12942. {
  12943. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12944. ctx->bc.Instr(asBC_TNZ);
  12945. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12946. }
  12947. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12948. }
  12949. else
  12950. {
  12951. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12952. Error(TXT_ILLEGAL_OPERATION, node);
  12953. #if AS_SIZEOF_BOOL == 1
  12954. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  12955. #else
  12956. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  12957. #endif
  12958. }
  12959. }
  12960. else
  12961. {
  12962. ConvertToVariableNotIn(lctx, rctx);
  12963. ConvertToVariableNotIn(rctx, lctx);
  12964. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12965. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12966. MergeExprBytecode(ctx, lctx);
  12967. MergeExprBytecode(ctx, rctx);
  12968. ProcessDeferredParams(ctx);
  12969. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  12970. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12971. iCmp = asBC_CMPi;
  12972. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12973. iCmp = asBC_CMPu;
  12974. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12975. iCmp = asBC_CMPi64;
  12976. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12977. iCmp = asBC_CMPu64;
  12978. else if( lctx->type.dataType.IsFloatType() )
  12979. iCmp = asBC_CMPf;
  12980. else if( lctx->type.dataType.IsDoubleType() )
  12981. iCmp = asBC_CMPd;
  12982. else
  12983. asASSERT(false);
  12984. if( op == ttEqual )
  12985. iT = asBC_TZ;
  12986. else if( op == ttNotEqual )
  12987. iT = asBC_TNZ;
  12988. else if( op == ttLessThan )
  12989. iT = asBC_TS;
  12990. else if( op == ttLessThanOrEqual )
  12991. iT = asBC_TNP;
  12992. else if( op == ttGreaterThan )
  12993. iT = asBC_TP;
  12994. else if( op == ttGreaterThanOrEqual )
  12995. iT = asBC_TNS;
  12996. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12997. int b = lctx->type.stackOffset;
  12998. int c = rctx->type.stackOffset;
  12999. ctx->bc.InstrW_W(iCmp, b, c);
  13000. ctx->bc.Instr(iT);
  13001. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13002. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13003. }
  13004. }
  13005. else
  13006. {
  13007. if( to.IsBooleanType() )
  13008. {
  13009. if( op == ttEqual || op == ttNotEqual )
  13010. {
  13011. asDWORD lv, rv;
  13012. #if AS_SIZEOF_BOOL == 1
  13013. lv = lctx->type.GetConstantB();
  13014. rv = rctx->type.GetConstantB();
  13015. #else
  13016. lv = lctx->type.GetConstantDW();
  13017. rv = rctx->type.GetConstantDW();
  13018. #endif
  13019. // Make sure they are equal if not false
  13020. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  13021. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  13022. asDWORD v = 0;
  13023. if (op == ttEqual)
  13024. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13025. else if (op == ttNotEqual)
  13026. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13027. #if AS_SIZEOF_BOOL == 1
  13028. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  13029. #else
  13030. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  13031. #endif
  13032. }
  13033. else
  13034. {
  13035. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13036. Error(TXT_ILLEGAL_OPERATION, node);
  13037. }
  13038. }
  13039. else
  13040. {
  13041. int i = 0;
  13042. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13043. {
  13044. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  13045. if( v < 0 ) i = -1;
  13046. if( v > 0 ) i = 1;
  13047. }
  13048. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13049. {
  13050. asDWORD v1 = lctx->type.GetConstantDW();
  13051. asDWORD v2 = rctx->type.GetConstantDW();
  13052. if( v1 < v2 ) i = -1;
  13053. if( v1 > v2 ) i = 1;
  13054. }
  13055. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13056. {
  13057. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  13058. if( v < 0 ) i = -1;
  13059. if( v > 0 ) i = 1;
  13060. }
  13061. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13062. {
  13063. asQWORD v1 = lctx->type.GetConstantQW();
  13064. asQWORD v2 = rctx->type.GetConstantQW();
  13065. if( v1 < v2 ) i = -1;
  13066. if( v1 > v2 ) i = 1;
  13067. }
  13068. else if( lctx->type.dataType.IsFloatType() )
  13069. {
  13070. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  13071. if( v < 0 ) i = -1;
  13072. if( v > 0 ) i = 1;
  13073. }
  13074. else if( lctx->type.dataType.IsDoubleType() )
  13075. {
  13076. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  13077. if( v < 0 ) i = -1;
  13078. if( v > 0 ) i = 1;
  13079. }
  13080. if( op == ttEqual )
  13081. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13082. else if( op == ttNotEqual )
  13083. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13084. else if( op == ttLessThan )
  13085. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13086. else if( op == ttLessThanOrEqual )
  13087. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13088. else if( op == ttGreaterThan )
  13089. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13090. else if( op == ttGreaterThanOrEqual )
  13091. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13092. #if AS_SIZEOF_BOOL == 1
  13093. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  13094. #else
  13095. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  13096. #endif
  13097. }
  13098. }
  13099. }
  13100. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  13101. {
  13102. // Put the result on the stack
  13103. if( asReference )
  13104. {
  13105. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  13106. ctx->type.dataType.MakeReference(true);
  13107. }
  13108. else
  13109. {
  13110. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13111. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  13112. else
  13113. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  13114. }
  13115. }
  13116. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  13117. {
  13118. // Both operands must be booleans
  13119. asCDataType to;
  13120. to.SetTokenType(ttBool);
  13121. // Do the actual conversion
  13122. int l = int(reservedVariables.GetLength());
  13123. rctx->bc.GetVarsUsed(reservedVariables);
  13124. lctx->bc.GetVarsUsed(reservedVariables);
  13125. // Allow value types to be converted to bool using 'bool opImplConv()'
  13126. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13127. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13128. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13129. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13130. reservedVariables.SetLength(l);
  13131. // Verify that the conversion was successful
  13132. if( !lctx->type.dataType.IsBooleanType() )
  13133. {
  13134. asCString str;
  13135. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13136. Error(str, node);
  13137. // Force the conversion to allow compilation to proceed
  13138. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13139. }
  13140. if( !rctx->type.dataType.IsBooleanType() )
  13141. {
  13142. asCString str;
  13143. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13144. Error(str, node);
  13145. // Force the conversion to allow compilation to proceed
  13146. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13147. }
  13148. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13149. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13150. // What kind of operator is it?
  13151. if( op == ttUnrecognizedToken )
  13152. op = node->tokenType;
  13153. if( op == ttXor )
  13154. {
  13155. if( !isConstant )
  13156. {
  13157. // Must convert to temporary variable, because we are changing the value before comparison
  13158. ConvertToTempVariableNotIn(lctx, rctx);
  13159. ConvertToTempVariableNotIn(rctx, lctx);
  13160. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13161. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13162. // Make sure they are equal if not false
  13163. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  13164. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  13165. MergeExprBytecode(ctx, lctx);
  13166. MergeExprBytecode(ctx, rctx);
  13167. ProcessDeferredParams(ctx);
  13168. int a = AllocateVariable(ctx->type.dataType, true);
  13169. int b = lctx->type.stackOffset;
  13170. int c = rctx->type.stackOffset;
  13171. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  13172. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13173. }
  13174. else
  13175. {
  13176. // Make sure they are equal if not false
  13177. #if AS_SIZEOF_BOOL == 1
  13178. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13179. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13180. asBYTE v = 0;
  13181. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  13182. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13183. ctx->type.isConstant = true;
  13184. ctx->type.SetConstantB(v);
  13185. #else
  13186. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13187. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13188. asDWORD v = 0;
  13189. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  13190. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13191. ctx->type.isConstant = true;
  13192. ctx->type.SetConstantDW(v);
  13193. #endif
  13194. }
  13195. }
  13196. else if( op == ttAnd ||
  13197. op == ttOr )
  13198. {
  13199. if( !isConstant )
  13200. {
  13201. // If or-operator and first value is 1 the second value shouldn't be calculated
  13202. // if and-operator and first value is 0 the second value shouldn't be calculated
  13203. ConvertToVariable(lctx);
  13204. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13205. MergeExprBytecode(ctx, lctx);
  13206. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  13207. int label1 = nextLabel++;
  13208. int label2 = nextLabel++;
  13209. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  13210. ctx->bc.Instr(asBC_ClrHi);
  13211. if( op == ttAnd )
  13212. {
  13213. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  13214. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  13215. ctx->bc.InstrINT(asBC_JMP, label2);
  13216. }
  13217. else if( op == ttOr )
  13218. {
  13219. ctx->bc.InstrDWORD(asBC_JZ, label1);
  13220. #if AS_SIZEOF_BOOL == 1
  13221. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13222. #else
  13223. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13224. #endif
  13225. ctx->bc.InstrINT(asBC_JMP, label2);
  13226. }
  13227. ctx->bc.Label((short)label1);
  13228. ConvertToVariable(rctx);
  13229. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13230. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  13231. MergeExprBytecode(ctx, rctx);
  13232. ctx->bc.Label((short)label2);
  13233. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  13234. }
  13235. else
  13236. {
  13237. #if AS_SIZEOF_BOOL == 1
  13238. asBYTE v = 0;
  13239. if( op == ttAnd )
  13240. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  13241. else if( op == ttOr )
  13242. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  13243. // Remember the result
  13244. ctx->type.isConstant = true;
  13245. ctx->type.SetConstantB(v);
  13246. #else
  13247. asDWORD v = 0;
  13248. if( op == ttAnd )
  13249. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  13250. else if( op == ttOr )
  13251. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  13252. // Remember the result
  13253. ctx->type.isConstant = true;
  13254. ctx->type.SetConstantDW(v);
  13255. #endif
  13256. }
  13257. }
  13258. }
  13259. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  13260. {
  13261. // Process the property accessor as get
  13262. ProcessPropertyGetAccessor(lctx, node);
  13263. ProcessPropertyGetAccessor(rctx, node);
  13264. DetermineSingleFunc(lctx, node);
  13265. DetermineSingleFunc(rctx, node);
  13266. // Make sure lctx doesn't end up with a variable used in rctx
  13267. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  13268. {
  13269. asCArray<int> vars;
  13270. rctx->bc.GetVarsUsed(vars);
  13271. int offset = AllocateVariable(lctx->type.dataType, true);
  13272. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  13273. ReleaseTemporaryVariable(offset, 0);
  13274. }
  13275. if( opToken == ttUnrecognizedToken )
  13276. opToken = node->tokenType;
  13277. // Warn if not both operands are explicit handles or null handles
  13278. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  13279. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  13280. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  13281. {
  13282. Warning(TXT_HANDLE_COMPARISON, node);
  13283. }
  13284. // If one of the operands is a value type used as handle, we should look for the opEquals method
  13285. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  13286. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  13287. (opToken == ttEqual || opToken == ttIs ||
  13288. opToken == ttNotEqual || opToken == ttNotIs) )
  13289. {
  13290. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  13291. // Find the matching opEquals method
  13292. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13293. if( r == 0 )
  13294. {
  13295. // Try again by switching the order of the operands
  13296. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13297. }
  13298. if( r == 1 )
  13299. {
  13300. if( opToken == ttNotEqual || opToken == ttNotIs )
  13301. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  13302. // Success, don't continue
  13303. return;
  13304. }
  13305. else if( r == 0 )
  13306. {
  13307. // Couldn't find opEquals method
  13308. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  13309. }
  13310. // Compiler error, don't continue
  13311. #if AS_SIZEOF_BOOL == 1
  13312. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13313. #else
  13314. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13315. #endif
  13316. return;
  13317. }
  13318. // Implicitly convert null to the other type
  13319. asCDataType to;
  13320. if( lctx->type.IsNullConstant() )
  13321. to = rctx->type.dataType;
  13322. else if( rctx->type.IsNullConstant() )
  13323. to = lctx->type.dataType;
  13324. else
  13325. {
  13326. // Find a common base type
  13327. asCExprContext tmp(engine);
  13328. tmp.type = rctx->type;
  13329. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  13330. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  13331. to = lctx->type.dataType;
  13332. else
  13333. to = rctx->type.dataType;
  13334. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  13335. to.MakeHandleToConst(true);
  13336. }
  13337. // Need to pop the value if it is a null constant
  13338. if( lctx->type.IsNullConstant() )
  13339. lctx->bc.Instr(asBC_PopPtr);
  13340. if( rctx->type.IsNullConstant() )
  13341. rctx->bc.Instr(asBC_PopPtr);
  13342. // Convert both sides to explicit handles
  13343. to.MakeHandle(true);
  13344. to.MakeReference(false);
  13345. if( !to.IsObjectHandle() )
  13346. {
  13347. // Compiler error, don't continue
  13348. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13349. #if AS_SIZEOF_BOOL == 1
  13350. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13351. #else
  13352. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13353. #endif
  13354. return;
  13355. }
  13356. // Do the conversion
  13357. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13358. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13359. // Both operands must be of the same type
  13360. // Verify that the conversion was successful
  13361. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13362. {
  13363. asCString str;
  13364. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13365. Error(str, node);
  13366. }
  13367. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13368. {
  13369. asCString str;
  13370. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13371. Error(str, node);
  13372. }
  13373. // Make sure it really is handles that are being compared
  13374. if( !lctx->type.dataType.IsObjectHandle() )
  13375. {
  13376. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13377. }
  13378. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13379. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  13380. {
  13381. // Make sure handles received as parameters by reference are copied to a local variable before the
  13382. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  13383. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  13384. lctx->type.isVariable = false;
  13385. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  13386. rctx->type.isVariable = false;
  13387. // TODO: runtime optimize: don't do REFCPY if not necessary
  13388. ConvertToVariableNotIn(lctx, rctx);
  13389. ConvertToVariable(rctx);
  13390. // Pop the pointers from the stack as they will not be used
  13391. lctx->bc.Instr(asBC_PopPtr);
  13392. rctx->bc.Instr(asBC_PopPtr);
  13393. MergeExprBytecode(ctx, lctx);
  13394. MergeExprBytecode(ctx, rctx);
  13395. int a = AllocateVariable(ctx->type.dataType, true);
  13396. int b = lctx->type.stackOffset;
  13397. int c = rctx->type.stackOffset;
  13398. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  13399. if( opToken == ttEqual || opToken == ttIs )
  13400. ctx->bc.Instr(asBC_TZ);
  13401. else if( opToken == ttNotEqual || opToken == ttNotIs )
  13402. ctx->bc.Instr(asBC_TNZ);
  13403. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13404. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13405. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  13406. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  13407. ProcessDeferredParams(ctx);
  13408. }
  13409. else
  13410. {
  13411. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13412. Error(TXT_ILLEGAL_OPERATION, node);
  13413. }
  13414. }
  13415. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  13416. {
  13417. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  13418. // A shared object may not call non-shared functions
  13419. if( outFunc->IsShared() && !descr->IsShared() )
  13420. {
  13421. asCString msg;
  13422. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  13423. Error(msg, ctx->exprNode);
  13424. }
  13425. // Check if the function is private or protected
  13426. if (descr->IsPrivate())
  13427. {
  13428. asCObjectType *type = descr->objectType;
  13429. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13430. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13431. asASSERT(type);
  13432. if( (type != outFunc->GetObjectType()) )
  13433. {
  13434. asCString msg;
  13435. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13436. Error(msg, ctx->exprNode);
  13437. }
  13438. }
  13439. else if (descr->IsProtected())
  13440. {
  13441. asCObjectType *type = descr->objectType;
  13442. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13443. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13444. asASSERT(type);
  13445. if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type))))
  13446. {
  13447. asCString msg;
  13448. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13449. Error(msg, ctx->exprNode);
  13450. }
  13451. }
  13452. int argSize = descr->GetSpaceNeededForArguments();
  13453. // If we're calling a class method we must make sure the object is guaranteed to stay
  13454. // alive throughout the call by holding on to a reference in a local variable. This must
  13455. // be done for any methods that return references, and any calls on script objects.
  13456. // Application registered objects are assumed to know to keep themselves alive even
  13457. // if the method doesn't return a reference.
  13458. if( !ctx->type.isRefSafe &&
  13459. descr->objectType &&
  13460. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  13461. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  13462. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  13463. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  13464. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  13465. {
  13466. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  13467. // local variable and then refer to the same for each call. An alias for the global variable
  13468. // should be stored in the variable scope so that the compiler can find it. For loops and
  13469. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  13470. // higher scope to increase the probability of re-use.
  13471. int tempRef = AllocateVariable(ctx->type.dataType, true);
  13472. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  13473. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  13474. // Add the release of this reference as a deferred expression
  13475. asSDeferredParam deferred;
  13476. deferred.origExpr = 0;
  13477. deferred.argInOutFlags = asTM_INREF;
  13478. deferred.argNode = 0;
  13479. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  13480. ctx->deferredParams.PushLast(deferred);
  13481. // Forget the current type
  13482. ctx->type.SetDummy();
  13483. }
  13484. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  13485. if( descr->DoesReturnOnStack() && !useVariable )
  13486. {
  13487. useVariable = true;
  13488. varOffset = AllocateVariable(descr->returnType, true);
  13489. // Push the pointer to the pre-allocated space for the return value
  13490. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  13491. if( descr->objectType )
  13492. {
  13493. // The object pointer is already on the stack, but should be the top
  13494. // one, so we need to swap the pointers in order to get the correct
  13495. ctx->bc.Instr(asBC_SwapPtr);
  13496. }
  13497. }
  13498. if( isConstructor )
  13499. {
  13500. // Sometimes the value types are allocated on the heap,
  13501. // which is when this way of constructing them is used.
  13502. asASSERT(useVariable == false);
  13503. if( (objType->flags & asOBJ_TEMPLATE) )
  13504. {
  13505. asASSERT( descr->funcType == asFUNC_SCRIPT );
  13506. // Find the id of the real constructor and not the generated stub
  13507. asUINT id = 0;
  13508. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  13509. while( bc )
  13510. {
  13511. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  13512. {
  13513. id = asBC_INTARG(bc);
  13514. break;
  13515. }
  13516. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  13517. }
  13518. asASSERT( id );
  13519. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  13520. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  13521. }
  13522. else
  13523. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  13524. // The instruction has already moved the returned object to the variable
  13525. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  13526. ctx->type.isLValue = false;
  13527. // Clean up arguments
  13528. if( args )
  13529. AfterFunctionCall(funcId, *args, ctx, false);
  13530. ProcessDeferredParams(ctx);
  13531. return;
  13532. }
  13533. else
  13534. {
  13535. if( descr->objectType )
  13536. argSize += AS_PTR_SIZE;
  13537. // If the function returns an object by value the address of the location
  13538. // where the value should be stored is passed as an argument too
  13539. if( descr->DoesReturnOnStack() )
  13540. argSize += AS_PTR_SIZE;
  13541. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  13542. // should be made with asBC_CALL as it is faster. Examples where this
  13543. // is known is for example finalled methods where the class doesn't derive
  13544. // from any other, or even non-finalled methods but where it is known
  13545. // at compile time the true type of the object. The first should be
  13546. // quite easy to determine, but the latter will be quite complex and possibly
  13547. // not worth it.
  13548. if( descr->funcType == asFUNC_IMPORTED )
  13549. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  13550. // TODO: Maybe we need two different byte codes
  13551. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  13552. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  13553. else if( descr->funcType == asFUNC_SCRIPT )
  13554. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  13555. else if( descr->funcType == asFUNC_SYSTEM )
  13556. {
  13557. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  13558. // type &obj::func(int)
  13559. // type &obj::func(uint)
  13560. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  13561. descr->parameterTypes.GetLength() == 1 &&
  13562. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  13563. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  13564. !descr->parameterTypes[0].IsReference() )
  13565. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  13566. else
  13567. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  13568. }
  13569. else if( descr->funcType == asFUNC_FUNCDEF )
  13570. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  13571. }
  13572. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  13573. {
  13574. int returnOffset = 0;
  13575. asCExprValue tmpExpr = ctx->type;
  13576. if( descr->DoesReturnOnStack() )
  13577. {
  13578. asASSERT( useVariable );
  13579. // The variable was allocated before the function was called
  13580. returnOffset = varOffset;
  13581. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13582. // The variable was initialized by the function, so we need to mark it as initialized here
  13583. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  13584. }
  13585. else
  13586. {
  13587. if( useVariable )
  13588. {
  13589. // Use the given variable
  13590. returnOffset = varOffset;
  13591. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  13592. }
  13593. else
  13594. {
  13595. // Allocate a temporary variable for the returned object
  13596. // The returned object will actually be allocated on the heap, so
  13597. // we must force the allocation of the variable to do the same
  13598. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  13599. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13600. }
  13601. // Move the pointer from the object register to the temporary variable
  13602. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  13603. }
  13604. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13605. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  13606. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  13607. // Clean up arguments
  13608. if( args )
  13609. AfterFunctionCall(funcId, *args, ctx, false);
  13610. ProcessDeferredParams(ctx);
  13611. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  13612. }
  13613. else if( descr->returnType.IsReference() )
  13614. {
  13615. asASSERT(useVariable == false);
  13616. // We cannot clean up the arguments yet, because the
  13617. // reference might be pointing to one of them.
  13618. if( args )
  13619. AfterFunctionCall(funcId, *args, ctx, true);
  13620. // Do not process the output parameters yet, because it
  13621. // might invalidate the returned reference
  13622. // If the context holds a variable that needs cleanup
  13623. // store it as a deferred parameter so it will be cleaned up
  13624. // afterwards.
  13625. if( ctx->type.isTemporary )
  13626. {
  13627. asSDeferredParam defer;
  13628. defer.argNode = 0;
  13629. defer.argType = ctx->type;
  13630. defer.argInOutFlags = asTM_INOUTREF;
  13631. defer.origExpr = 0;
  13632. ctx->deferredParams.PushLast(defer);
  13633. }
  13634. ctx->type.Set(descr->returnType);
  13635. if( !descr->returnType.IsPrimitive() )
  13636. {
  13637. ctx->bc.Instr(asBC_PshRPtr);
  13638. if( descr->returnType.IsObject() &&
  13639. !descr->returnType.IsObjectHandle() )
  13640. {
  13641. // We are getting the pointer to the object
  13642. // not a pointer to a object variable
  13643. ctx->type.dataType.MakeReference(false);
  13644. }
  13645. }
  13646. // A returned reference can be used as lvalue
  13647. ctx->type.isLValue = true;
  13648. }
  13649. else
  13650. {
  13651. asCExprValue tmpExpr = ctx->type;
  13652. if( descr->returnType.GetSizeInMemoryBytes() )
  13653. {
  13654. int offset;
  13655. if (useVariable)
  13656. offset = varOffset;
  13657. else
  13658. {
  13659. // Allocate a temporary variable to hold the value, but make sure
  13660. // the temporary variable isn't used in any of the deferred arguments
  13661. int l = int(reservedVariables.GetLength());
  13662. for (asUINT n = 0; args && n < args->GetLength(); n++)
  13663. {
  13664. asCExprContext *expr = (*args)[n]->origExpr;
  13665. if (expr)
  13666. expr->bc.GetVarsUsed(reservedVariables);
  13667. }
  13668. offset = AllocateVariable(descr->returnType, true);
  13669. reservedVariables.SetLength(l);
  13670. }
  13671. ctx->type.SetVariable(descr->returnType, offset, true);
  13672. // Move the value from the return register to the variable
  13673. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  13674. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  13675. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  13676. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  13677. }
  13678. else
  13679. ctx->type.Set(descr->returnType);
  13680. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13681. ctx->type.isLValue = false;
  13682. // Clean up arguments
  13683. if( args )
  13684. AfterFunctionCall(funcId, *args, ctx, false);
  13685. ProcessDeferredParams(ctx);
  13686. }
  13687. }
  13688. // This only merges the bytecode, but doesn't modify the type of the final context
  13689. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  13690. {
  13691. before->bc.AddCode(&after->bc);
  13692. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  13693. {
  13694. before->deferredParams.PushLast(after->deferredParams[n]);
  13695. after->deferredParams[n].origExpr = 0;
  13696. }
  13697. after->deferredParams.SetLength(0);
  13698. }
  13699. // This merges both bytecode and the type of the final context
  13700. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  13701. {
  13702. MergeExprBytecode(before, after);
  13703. before->Merge(after);
  13704. }
  13705. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  13706. {
  13707. if( funcs.GetLength() == 0 ) return;
  13708. // This is only done for object methods
  13709. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  13710. if( !desc || desc->objectType == 0 ) return;
  13711. // Check if there are any non-const matches
  13712. asUINT n;
  13713. bool foundNonConst = false;
  13714. for( n = 0; n < funcs.GetLength(); n++ )
  13715. {
  13716. desc = builder->GetFunctionDescription(funcs[n]);
  13717. if( desc && desc->IsReadOnly() != removeConst )
  13718. {
  13719. foundNonConst = true;
  13720. break;
  13721. }
  13722. }
  13723. if( foundNonConst )
  13724. {
  13725. // Remove all const methods
  13726. for( n = 0; n < funcs.GetLength(); n++ )
  13727. {
  13728. desc = builder->GetFunctionDescription(funcs[n]);
  13729. if( desc && desc->IsReadOnly() == removeConst )
  13730. {
  13731. if( n == funcs.GetLength() - 1 )
  13732. funcs.PopLast();
  13733. else
  13734. funcs[n] = funcs.PopLast();
  13735. n--;
  13736. }
  13737. }
  13738. }
  13739. }
  13740. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13741. asCExprValue::asCExprValue()
  13742. {
  13743. isTemporary = false;
  13744. stackOffset = 0;
  13745. isConstant = false;
  13746. isVariable = false;
  13747. isExplicitHandle = false;
  13748. qwordValue = 0;
  13749. isLValue = false;
  13750. isRefToLocal = false;
  13751. isRefSafe = false;
  13752. }
  13753. void asCExprValue::Set(const asCDataType &dt)
  13754. {
  13755. dataType = dt;
  13756. isTemporary = false;
  13757. stackOffset = 0;
  13758. isConstant = false;
  13759. isVariable = false;
  13760. isExplicitHandle = false;
  13761. qwordValue = 0;
  13762. isLValue = false;
  13763. isRefToLocal = false;
  13764. isRefSafe = false;
  13765. }
  13766. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  13767. {
  13768. Set(in_dt);
  13769. this->isVariable = true;
  13770. this->isTemporary = in_isTemporary;
  13771. this->stackOffset = (short)in_stackOffset;
  13772. }
  13773. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  13774. {
  13775. Set(dt);
  13776. isConstant = true;
  13777. SetConstantQW(value);
  13778. }
  13779. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  13780. {
  13781. Set(dt);
  13782. isConstant = true;
  13783. SetConstantDW(value);
  13784. }
  13785. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  13786. {
  13787. Set(dt);
  13788. isConstant = true;
  13789. SetConstantB(value);
  13790. }
  13791. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  13792. {
  13793. Set(dt);
  13794. isConstant = true;
  13795. SetConstantW(value);
  13796. }
  13797. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  13798. {
  13799. Set(dt);
  13800. isConstant = true;
  13801. SetConstantF(value);
  13802. }
  13803. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  13804. {
  13805. Set(dt);
  13806. isConstant = true;
  13807. SetConstantD(value);
  13808. }
  13809. void asCExprValue::SetConstantQW(asQWORD value)
  13810. {
  13811. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13812. qwordValue = value;
  13813. }
  13814. void asCExprValue::SetConstantDW(asDWORD value)
  13815. {
  13816. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13817. dwordValue = value;
  13818. }
  13819. void asCExprValue::SetConstantW(asWORD value)
  13820. {
  13821. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13822. wordValue = value;
  13823. }
  13824. void asCExprValue::SetConstantB(asBYTE value)
  13825. {
  13826. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  13827. byteValue = value;
  13828. }
  13829. void asCExprValue::SetConstantF(float value)
  13830. {
  13831. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13832. floatValue = value;
  13833. }
  13834. void asCExprValue::SetConstantD(double value)
  13835. {
  13836. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13837. doubleValue = value;
  13838. }
  13839. asQWORD asCExprValue::GetConstantQW()
  13840. {
  13841. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13842. return qwordValue;
  13843. }
  13844. asDWORD asCExprValue::GetConstantDW()
  13845. {
  13846. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13847. return dwordValue;
  13848. }
  13849. asWORD asCExprValue::GetConstantW()
  13850. {
  13851. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13852. return wordValue;
  13853. }
  13854. asBYTE asCExprValue::GetConstantB()
  13855. {
  13856. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  13857. return byteValue;
  13858. }
  13859. float asCExprValue::GetConstantF()
  13860. {
  13861. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13862. return floatValue;
  13863. }
  13864. double asCExprValue::GetConstantD()
  13865. {
  13866. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13867. return doubleValue;
  13868. }
  13869. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  13870. {
  13871. Set(dt);
  13872. isConstant = true;
  13873. // This code is necessary to guarantee that the code
  13874. // works on both big endian and little endian CPUs.
  13875. if (dataType.GetSizeInMemoryBytes() == 1)
  13876. byteValue = (asBYTE)qw;
  13877. if (dataType.GetSizeInMemoryBytes() == 2)
  13878. wordValue = (asWORD)qw;
  13879. if (dataType.GetSizeInMemoryBytes() == 4)
  13880. dwordValue = (asDWORD)qw;
  13881. else
  13882. qwordValue = qw;
  13883. }
  13884. asQWORD asCExprValue::GetConstantData()
  13885. {
  13886. asQWORD qw = 0;
  13887. // This code is necessary to guarantee that the code
  13888. // works on both big endian and little endian CPUs.
  13889. if (dataType.GetSizeInMemoryBytes() == 1)
  13890. qw = byteValue;
  13891. if (dataType.GetSizeInMemoryBytes() == 2)
  13892. qw = wordValue;
  13893. if (dataType.GetSizeInMemoryBytes() == 4)
  13894. qw = dwordValue;
  13895. else
  13896. qw = qwordValue;
  13897. return qw;
  13898. }
  13899. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  13900. {
  13901. // This is used for when the expression evaluates to a
  13902. // function, but it is not yet known exactly which. The
  13903. // owner expression will hold the name of the function
  13904. // to determine the exact function when the signature is
  13905. // known.
  13906. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  13907. isConstant = true;
  13908. isExplicitHandle = false;
  13909. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  13910. isLValue = false;
  13911. }
  13912. bool asCExprValue::IsUndefinedFuncHandle() const
  13913. {
  13914. if (isConstant == false) return false;
  13915. if (qwordValue == 0) return false;
  13916. if (isLValue) return false;
  13917. if (dataType.GetTypeInfo() == 0) return false;
  13918. if (dataType.GetTypeInfo()->name != "$func") return false;
  13919. if (dataType.IsFuncdef()) return false;
  13920. return true;
  13921. }
  13922. void asCExprValue::SetNullConstant()
  13923. {
  13924. Set(asCDataType::CreateNullHandle());
  13925. isConstant = true;
  13926. isExplicitHandle = false;
  13927. qwordValue = 0;
  13928. isLValue = false;
  13929. }
  13930. bool asCExprValue::IsNullConstant() const
  13931. {
  13932. // We can't check the actual object type, because the null constant may have been cast to another type
  13933. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  13934. return true;
  13935. return false;
  13936. }
  13937. void asCExprValue::SetVoid()
  13938. {
  13939. Set(asCDataType::CreatePrimitive(ttVoid, false));
  13940. isLValue = false;
  13941. isConstant = true;
  13942. }
  13943. bool asCExprValue::IsVoid() const
  13944. {
  13945. if (dataType.GetTokenType() == ttVoid)
  13946. return true;
  13947. return false;
  13948. }
  13949. void asCExprValue::SetDummy()
  13950. {
  13951. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  13952. }
  13953. ////////////////////////////////////////////////////////////////////////////////////////////////
  13954. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  13955. {
  13956. property_arg = 0;
  13957. Clear();
  13958. }
  13959. asCExprContext::~asCExprContext()
  13960. {
  13961. if (property_arg)
  13962. asDELETE(property_arg, asCExprContext);
  13963. }
  13964. void asCExprContext::Clear()
  13965. {
  13966. bc.ClearAll();
  13967. type.Set(asCDataType());
  13968. deferredParams.SetLength(0);
  13969. if (property_arg)
  13970. asDELETE(property_arg, asCExprContext);
  13971. property_arg = 0;
  13972. exprNode = 0;
  13973. origExpr = 0;
  13974. property_get = 0;
  13975. property_set = 0;
  13976. property_const = false;
  13977. property_handle = false;
  13978. property_ref = false;
  13979. methodName = "";
  13980. enumValue = "";
  13981. symbolNamespace = 0;
  13982. isVoidExpression = false;
  13983. isCleanArg = false;
  13984. isAnonymousInitList = false;
  13985. origCode = 0;
  13986. }
  13987. bool asCExprContext::IsClassMethod() const
  13988. {
  13989. if (type.dataType.GetTypeInfo() == 0) return false;
  13990. if (methodName == "") return false;
  13991. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  13992. if (isAnonymousInitList) return false;
  13993. return true;
  13994. }
  13995. bool asCExprContext::IsGlobalFunc() const
  13996. {
  13997. if (type.dataType.GetTypeInfo() == 0) return false;
  13998. if (methodName == "") return false;
  13999. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14000. if (isAnonymousInitList) return false;
  14001. return true;
  14002. }
  14003. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  14004. {
  14005. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  14006. asASSERT(bc.GetLastInstr() == -1);
  14007. Clear();
  14008. type.SetUndefinedFuncHandle(bc.GetEngine());
  14009. exprNode = funcDecl;
  14010. }
  14011. bool asCExprContext::IsLambda() const
  14012. {
  14013. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  14014. return true;
  14015. return false;
  14016. }
  14017. void asCExprContext::SetVoidExpression()
  14018. {
  14019. Clear();
  14020. type.SetVoid();
  14021. isVoidExpression = true;
  14022. }
  14023. bool asCExprContext::IsVoidExpression() const
  14024. {
  14025. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  14026. return true;
  14027. return false;
  14028. }
  14029. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script)
  14030. {
  14031. Clear();
  14032. exprNode = initList;
  14033. origCode = script;
  14034. isAnonymousInitList = true;
  14035. }
  14036. bool asCExprContext::IsAnonymousInitList() const
  14037. {
  14038. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  14039. return true;
  14040. return false;
  14041. }
  14042. void asCExprContext::Merge(asCExprContext *after)
  14043. {
  14044. type = after->type;
  14045. property_get = after->property_get;
  14046. property_set = after->property_set;
  14047. property_const = after->property_const;
  14048. property_handle = after->property_handle;
  14049. property_ref = after->property_ref;
  14050. property_arg = after->property_arg;
  14051. exprNode = after->exprNode;
  14052. methodName = after->methodName;
  14053. enumValue = after->enumValue;
  14054. isVoidExpression = after->isVoidExpression;
  14055. isCleanArg = after->isCleanArg;
  14056. isAnonymousInitList = after->isAnonymousInitList;
  14057. origCode = after->origCode;
  14058. after->property_arg = 0;
  14059. // Do not copy the origExpr member
  14060. }
  14061. END_AS_NAMESPACE
  14062. #endif // AS_NO_COMPILER